这个问题涉及本质上相同的代码的两个不同的实现。
首先,使用delegate创建一个比较方法,该方法可以在对对象集合进行排序时用作参数:
class Foo
{
public static Comparison<Foo> BarComparison = delegate(Foo foo1, Foo foo2)
{
return foo1.Bar.CompareTo(foo2.Bar);
};
}当我想要以一种不同于CompareTo函数提供的方式对Foo对象集合进行排序时,我会使用上面的方法。例如:
List<Foo> fooList = new List<Foo>();
fooList.Sort(BarComparison);第二,使用IComparer:
public class BarComparer : IComparer<Foo>
{
public int Compare(Foo foo1, Foo foo2)
{
return foo1.Bar.CompareTo(foo2.Bar);
}
}当我想对Foo对象集合中的Foo对象进行二进制搜索时,我会使用上面的代码。例如:
BarComparer comparer = new BarComparer();
List<Foo> fooList = new List<Foo>();
Foo foo = new Foo();
int index = fooList.BinarySearch(foo, comparer);我的问题是:
发布于 2010-03-22 03:10:30
与IComparer<T>相比,接受Comparison<T>的最大优势可能是能够编写匿名方法。假设我有一个List<MyClass>,其中MyClass包含一个应该用于排序的ID属性,我可以这样写:
myList.Sort((c1, c2) => c1.ID.CompareTo(c2.ID));这比必须编写整个IComparer<MyClass>实现要方便得多。
除了与遗留代码(包括.NET IComparer<T>类)兼容之外,我不确定接受框架是否真的有什么主要优势。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));发布于 2010-03-22 03:03:48
在性能方面,这两个选项都没有优势。这实际上是一个方便性和代码可维护性的问题。选择您喜欢的选项。话虽如此,所讨论的方法会稍微限制您的选择。
您可以使用List.Sort的IComparer<T>接口,这将允许您不复制代码。
不幸的是,BinarySearch不使用Comparison<T>实现选项,因此您不能对该方法使用Comparison<T>委托(至少不能直接使用)。
如果您确实想将Comparison<T>用于这两者,您可以创建一个通用的IComparer<T>实现,该实现在其构造函数中接受一个Comparison<T>委托,并实现IComparer<T>。
public class ComparisonComparer<T> : IComparer<T>
{
private Comparison<T> method;
public ComparisonComparer(Comparison<T> comparison)
{
this.method = comparison;
}
public int Compare(T arg1, T arg2)
{
return method(arg1, arg2);
}
}发布于 2010-03-22 03:05:02
委托技术非常短(lambda表达式可能更短),所以如果您的目标是代码更短,那么这是一个优势。
但是,实现IComparer (和它的泛型等效项)会使代码更具可测试性:您可以在比较类/方法中添加一些单元测试。
此外,当组合两个或更多比较器并将它们组合为新的比较器时,您可以重用比较器实现。使用匿名委托的代码重用更难实现。
所以,总结一下:
匿名委派:更短(也许更干净)的代码
显式实现:可测试性和代码重用。
https://stackoverflow.com/questions/2488298
复制相似问题