Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the best way to have a Generic Comparer

Tags:

c#

generics

I have a lot of comparer classes where the class being compared is simply checking the name property of the object and doing a string compare. For example:

public class ExerciseSorter : IComparer<Exercise>
{
    public int Compare(Exercise x, Exercise y)
    {
        return String.Compare(x.Name, y.Name);
    }
}

public class CarSorter : IComparer<Car>
{
    public int Compare(Car x, Car y)
    {
        return String.Compare(x.Name, y.Name);
    }
}

what is the best way to have this code generic so i dont need to write redundant code over and over again.

like image 416
leora Avatar asked Apr 01 '10 03:04

leora


People also ask

How do you compare type T?

If you need to compare objects of type T for equality/inequality, you can use the IEquatable<T> interface.

What is the comparer class used for?

Objects Comparer framework provides a mechanism to compare complex objects, and allows us to override comparison rules for specific properties and types.

What is the difference between IComparer and IComparable in C#?

IComparer compares two objects that it's given. IComparable is implemented by the object that is being compared, for the purpose of comparing with another one of itself.

How do I compare generic types in C#?

To enable two objects of a generic type parameter to be compared, they must implement the IComparable or IComparable<T>, and/or IEquatable<T> interfaces. Both versions of IComparable define the CompareTo() method and IEquatable<T> defines the Equals() method.


2 Answers

I use one like this:

public class AnonymousComparer<T> : IComparer<T>
{
    private Comparison<T> comparison;

    public AnonymousComparer(Comparison<T> comparison)
    {
        if (comparison == null)
            throw new ArgumentNullException("comparison");
        this.comparison = comparison;
    }

    public int Compare(T x, T y)
    {
        return comparison(x, y);
    }
}

Usage:

var carComparer = new AnonymousComparer<Car>((x, y) => x.Name.CompareTo(y.Name));

If you're doing a straight property compare and the property type implements IComparable (for example an int or string), then, I also have this class which is a bit more terse to use:

public class PropertyComparer<T, TProp> : IComparer<T>
    where TProp : IComparable
{
    private Func<T, TProp> func;

    public PropertyComparer(Func<T, TProp> func)
    {
        if (func == null)
            throw new ArgumentNullException("func");
        this.func = func;
    }

    public int Compare(T x, T y)
    {
        TProp px = func(x);
        TProp py = func(y);
        return px.CompareTo(py);
    }
}

Usage of this one is:

var carComparer = new PropertyComparer<Car, string>(c => c.Name);
like image 192
Aaronaught Avatar answered Sep 22 '22 17:09

Aaronaught


As of .NET 4.5, creating a generic class to wrap a Comparison<T> delegate in an IComparer<T> interface implementation is not needed.

The framework offers the static Create method on the Comparer<T> class which takes a Comparison<T> delegate and returns a Comparer<T> (which implements IComparer<T>).

Here's an example of how to use it:

// Sample comparison, any T will do.
Comparison<int> comparison = (x, y) => x.CompareTo(y)

// Get the IComparer.
IComparer<T> comparer = Comparer.Create(comparison);

Now, you can write lambda expressions which perform your comparisons and quickly wrap those in IComparer<T> implementations where an option to take a Comparison<T> delegate is not offered (such as the Sort method on the List<T> class).

like image 44
casperOne Avatar answered Sep 23 '22 17:09

casperOne