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);
}
}
精彩评论