C#lambda表达式和IComparer
我使用lambda表达式在C#中排序和搜索数组。 我不想在我的类中实现IComparer接口,因为我需要对多个成员字段进行排序和搜索。
class Widget { public int foo; public void Bar() { Widget[] widgets; Array.Sort(widgets, (a, b) => a.foo.CompareTo(b.foo)); Widget x = new Widget(); x.foo = 5; int index = Array.BinarySearch(widgets, x, (a, b) => a.foo.CompareTo(b.foo)); } }
虽然排序工作正常,但二进制搜索会产生编译错误无法将lambda表达式转换为类型’System.Collections.IComparer ‘,因为它不是委托类型 。 由于某种原因,Sort对IComparer和Comparison都有重载,但BinarySearch只支持IComparer。 经过一些研究,我发现了ComparisonComparer
笨重的ComparisonComparer
将比较转换为IComparer:
public class ComparisonComparer : IComparer { private readonly Comparison comparison; public ComparisonComparer(Comparison comparison) { this.comparison = comparison; } int IComparer.Compare(T x, T y) { return comparison(x, y); } }
这允许二进制搜索如下工作:
int index = Array.BinarySearch( widgets, x, new ComparisonComparer((a, b) => a.foo.CompareTo(b.foo)));
呸。 有更干净的方式吗?
好吧,一个选择是创建类似ProjectionComparer
东西。 我在MiscUtil中有一个版本 – 它基本上是从投影中创建一个IComparer
。
所以你的例子是:
int index = Array.BinarySearch(widgets, x, ProjectionComparer.Create(x => x.foo));
或者你可以在T[]
上实现自己的扩展方法来做同样的事情:
public static int BinarySearchBy( this TSource[] array, TSource value, Func keySelector) { return Array.BinarySearch(array, value, ProjectionComparer.Create(array, keySelector)); }
您可以使用我的ValueComparer
类 :
int index = Array.BinarySearch( widgets, x, new ValueComparer(x => x.Foo) );
您可以通过传递多个lambda表达式来比较多个属性。
试试这个:
public static class ComparisonEx { public static IComparer AsComparer (this Comparison @this) { if (@this == null) throw new System.ArgumentNullException("Comparison @this"); return new ComparisonComparer (@this); } public static IComparer AsComparer (this Func @this) { if (@this == null) throw new System.ArgumentNullException("Func @this"); return new ComparisonComparer ((x, y) => @this(x, y)); } private class ComparisonComparer : IComparer { public ComparisonComparer(Comparison comparison) { if (comparison == null) throw new System.ArgumentNullException("comparison"); this.Comparison = comparison; } public int Compare(T x, T y) { return this.Comparison(x, y); } public Comparison Comparison { get; private set; } } }
它允许您使用此代码:
Comparison c = (x, y) => x == y ? 0 : (x <= y ? -1 : 1); IComparer icc = c.AsComparer(); Func f = (x, y) => x == y ? 0 : (x <= y ? -1 : 1); IComparer icf = f.AsComparer();