tags:

views:

76

answers:

2

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.

+7  A: 

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);
Aaronaught
var carComparer = new AnonymousComparer<Car>((x,y)=>x.Name.CompareTo(y.Name)) ?
spender
@spender: Yes, that is the usage... did I make a mistake? That looks the same as what I wrote.
Aaronaught
1st edition was var carComparer = new AnonymousComparer<Car>(x.Name.CompareTo(y.Name)) . Is correct now.
spender
A: 

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);
    }
}
Konstantin Spirin