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.
If you need to compare objects of type T for equality/inequality, you can use the IEquatable<T> interface.
Objects Comparer framework provides a mechanism to compare complex objects, and allows us to override comparison rules for specific properties and types.
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.
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.
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 you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With