Вероятно, самым большим преимуществом принятия Comparison<T>
по сравнению с IComparer<T>
является возможность писать анонимные методы. Если у меня есть, скажем, List<MyClass>
, где MyClass
содержит свойство ID
, которое должно использоваться для сортировки, я могу написать:
myList.Sort((c1, c2) => c1.ID.CompareTo(c2.ID));
Это гораздо удобнее, чем писать целую IComparer<MyClass>
реализацию.
Я не уверен, что принятие IComparer<T>
действительно имеет какие-то серьезные преимущества, за исключением совместимости с устаревшим кодом (включая классы .NET Framework). Свойство Comparer<T>.Default
действительно полезно только для примитивных типов; все остальное обычно требует дополнительной работы для кодирования.
Чтобы избежать дублирования кода, когда мне нужно работать с IComparer<T>
, я обычно делаю одну вещь: создаю универсальный компаратор, например:
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);
}
}
Это позволяет писать код, такой как:
myList.BinarySearch(item,
new AnonymousComparer<MyClass>(x.ID.CompareTo(y.ID)));
Это не совсем красиво, но экономит время.
У меня есть еще один полезный класс:
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);
}
}
Который вы можете написать код, предназначенный для IComparer<T>
как:
myList.BinarySearch(item, new PropertyComparer<MyClass, int>(c => c.ID));