开发者

what is the best way to have a Generic Comparer

I have a lot of comparer classe开发者_如何学Gos 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.


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);


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).


If all your classes have Name property, you could introduce IHaveName interface and create comparer like this:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜