传递一个lambdaexpression式来代替IComparer或IEqualityComparer或任何单一方法接口?
我碰巧看到一些代码,这个家伙传递一个lambdaexpression式到一个ArrayList.Sort(IComparer在这里)或一个IEnumerable.SequenceEqual(IEnumerable列表,IEqualityComparer在这里),其中IComparer或IEqualityComparer的预期。
我不能确定我是否看到它,或者我只是在做梦。 而且我似乎无法find任何这些集合中接受Func <>或其方法签名委托的扩展。
有没有这样的重载/延伸方法? 或者,如果没有,是否有可能像这样混淆,并传递一个algorithm(读委托)在哪里一个单一的方法接口预计?
更新谢谢大家。 我也这么想。 我一定是在做梦。 我知道如何写一个转换。 我只是不确定是否曾经见过这样的事情,或者只是以为我曾经见过这样的事情。
还有一个更新看,在这里,我find了一个这样的例子。 毕竟,我并不是在做梦。 看看这个人在这里做什么 。 是什么赋予了?
这里是另一个更新:好的,我明白了。 这家伙正在使用Comparison<T>
超载。 尼斯。 不错,但是完全容易误导你。 不错,但是。 谢谢。
我不太确定它的真正用处是什么,因为我认为在基本库中的大多数情况下,期望IComparer有一个超载,期望一个比较…但是只是为了logging:
在.Net 4.5中,他们添加了一个方法来从比较:比较器创build中获得一个IComparer
所以你可以将你的lambda传递给它并获得一个IComparer。
我也在网上search一个解决scheme,但我没有find任何满意的。 所以我创build了一个通用的EqualityComparerFactory:
public static class EqualityComparerFactory<T> { private class MyComparer : IEqualityComparer<T> { private readonly Func<T, int> _getHashCodeFunc; private readonly Func<T, T, bool> _equalsFunc; public MyComparer(Func<T, int> getHashCodeFunc, Func<T, T, bool> equalsFunc) { _getHashCodeFunc = getHashCodeFunc; _equalsFunc = equalsFunc; } public bool Equals(T x, T y) { return _equalsFunc(x, y); } public int GetHashCode(T obj) { return _getHashCodeFunc(obj); } } public static IEqualityComparer<T> CreateComparer(Func<T, int> getHashCodeFunc, Func<T, T, bool> equalsFunc) { if (getHashCodeFunc == null) throw new ArgumentNullException("getHashCodeFunc"); if (equalsFunc == null) throw new ArgumentNullException("equalsFunc"); return new MyComparer(getHashCodeFunc, equalsFunc); } }
这个想法是,CreateComparer方法有两个参数:一个委托给GetHashCode(T)和一个委托给Equals(T,T)
例:
class Person { public int Id { get; set; } public string LastName { get; set; } public string FirstName { get; set; } } class Program { static void Main(string[] args) { var list1 = new List<Person>(new[]{ new Person { Id = 1, FirstName = "Walter", LastName = "White" }, new Person { Id = 2, FirstName = "Jesse", LastName = "Pinkman" }, new Person { Id = 3, FirstName = "Skyler", LastName = "White" }, new Person { Id = 4, FirstName = "Hank", LastName = "Schrader" }, }); var list2 = new List<Person>(new[]{ new Person { Id = 1, FirstName = "Walter", LastName = "White" }, new Person { Id = 4, FirstName = "Hank", LastName = "Schrader" }, }); // We're comparing based on the Id property var comparer = EqualityComparerFactory<Person>.CreateComparer(a => a.Id.GetHashCode(), (a, b) => a.Id==b.Id); var intersection = list1.Intersect(list2, comparer).ToList(); } }
您可以为Array.Sort方法提供一个lambda,因为它需要一个方法来接受两个Ttypes的对象并返回一个整数。 因此,您可以提供以下定义(a, b) => a.CompareTo(b)
一个lambda (a, b) => a.CompareTo(b)
。 一个例子来做一个整数数组的降序sorting:
int[] array = { 1, 8, 19, 4 }; // descending sort Array.Sort(array, (a, b) => -1 * a.CompareTo(b));
public class Comparer2<T, TKey> : IComparer<T>, IEqualityComparer<T> { private readonly Expression<Func<T, TKey>> _KeyExpr; private readonly Func<T, TKey> _CompiledFunc // Constructor public Comparer2(Expression<Func<T, TKey>> getKey) { _KeyExpr = getKey; _CompiledFunc = _KeyExpr.Compile(); } public int Compare(T obj1, T obj2) { return Comparer<TKey>.Default.Compare(_CompiledFunc(obj1), _CompiledFunc(obj2)); } public bool Equals(T obj1, T obj2) { return EqualityComparer<TKey>.Default.Equals(_CompiledFunc(obj1), _CompiledFunc(obj2)); } public int GetHashCode(T obj) { return EqualityComparer<TKey>.Default.GetHashCode(_CompiledFunc(obj)); } }
像这样使用它
ArrayList.Sort(new Comparer2<Product, string>(p => p.Name));
我投票给梦想理论。
你不能在需要对象的地方传递一个函数:System.Delegate(这是lambdaexpression式)的衍生物不能实现这些接口。
你可能看到的是使用Converter<TInput, TOutput>
委托,它可以用lambdabuild模。 Array.ConvertAll使用这个委托的一个实例。
你不能直接传递它,但你可以通过定义一个除了Func<T,T,int>
之外的LambdaComparer
类,然后在CompareTo
使用它。
它不是很简洁,但可以通过Func
上的一些创造性扩展方法缩短它。
这些方法没有接受委托而不是接口的重载,但是:
- 您通常可以通过传递给
Enumerable.OrderBy
的委托返回更简单的sorting键 - 同样,您可以在调用
Enumerable.Select
之前调用Enumerable.SequenceEqual
- 应该很简单,编写一个包装,它根据
Func<T, T, bool>
实现IEqualityComparer<T>
Func<T, T, bool>
- F#可以让你用lambda来实现这种接口:)
如果你需要这个函数来使用lambda和可能的两种不同的元素types:
static class IEnumerableExtensions { public static bool SequenceEqual<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<T1, T2, bool> comparer) { if (first == null) throw new NullReferenceException("first"); if (second == null) throw new NullReferenceException("second"); using (IEnumerator<T1> e1 = first.GetEnumerator()) using (IEnumerator<T2> e2 = second.GetEnumerator()) { while (e1.MoveNext()) { if (!(e2.MoveNext() && comparer(e1.Current, e2.Current))) return false; } if (e2.MoveNext()) return false; } return true; } }