为LINQ的Distinct()使用相等比较器的委托
我有一个LINQ Distinct()语句,使用我自己的自定义比较器,如下所示:
class MyComparer<T> : IEqualityComparer<T> where T : MyType { public bool Equals(T x, T y) { return x.Id.Equals(y.Id); } public int GetHashCode(T obj) { return obj.Id.GetHashCode(); } } ... var distincts = bundle.GetAllThings.Distinct(new MyComparer<MySubType>());
这一切都很好,并按我的意愿工作。 出于好奇,我需要定义自己的比较器,还是可以用委托来replace它? 我以为我应该可以做这样的事情:
var distincts = bundle.GetAllThings.Distinct((a,b) => a.Id == b.Id);
但是这不能编译。 有一个巧妙的把戏吗?
不同的是,将IEqualityComparer作为第二个参数,因此您将需要一个IEqualityComparer。 尽pipe如此,制作一个通用代理并不难。 当然,这可能已经在一些地方实现了,比如MoreLINQ在其他答案中提到的一个。
你可以像这样实现它:
public static class Compare { public static IEnumerable<T> DistinctBy<T, TIdentity>(this IEnumerable<T> source, Func<T, TIdentity> identitySelector) { return source.Distinct(Compare.By(identitySelector)); } public static IEqualityComparer<TSource> By<TSource, TIdentity>(Func<TSource, TIdentity> identitySelector) { return new DelegateComparer<TSource, TIdentity>(identitySelector); } private class DelegateComparer<T, TIdentity> : IEqualityComparer<T> { private readonly Func<T, TIdentity> identitySelector; public DelegateComparer(Func<T, TIdentity> identitySelector) { this.identitySelector = identitySelector; } public bool Equals(T x, T y) { return Equals(identitySelector(x), identitySelector(y)); } public int GetHashCode(T obj) { return identitySelector(obj).GetHashCode(); } } }
这给你的语法:
source.DistinctBy(a => a.Id);
或者,如果你觉得这样更清楚:
source.Distinct(Compare.By(a => a.Id));
不幸的是, Distinct
不会出现这样的超载,所以你有什么是一个不错的select。
使用MoreLinq ,您可以使用DistinctBy
运算符。
var distincts = bundle.GetAllThings.DistinctBy(a => a.Id);
您可能还需要考虑编写一个通用的ProjectionEqualityComparer
,可以将相应的委托转换为IEqualityComparer<T>
实现,如下面所列的实现。
这个链接显示了如何创build扩展方法,以便能够以您所给的方式使用Distinct。 您需要编写两个Distinct
扩展方法和一个IEqualityComparer
。
这是来自网站的代码:
public static class Extensions { public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, Func<T, T, bool> comparer) { return source.Distinct(new DelegateComparer<T>(comparer)); } public static IEnumerable<T> Distinct<T>(this IEnumerable<T> source, Func<T, T, bool> comparer, Func<T,int> hashMethod) { return source.Distinct(new DelegateComparer<T>(comparer,hashMethod)); } } public class DelegateComparer<T> : IEqualityComparer<T> { private Func<T, T, bool> _equals; private Func<T,int> _getHashCode; public DelegateComparer(Func<T, T, bool> equals) { this._equals = equals; } public DelegateComparer(Func<T, T, bool> equals, Func<T,int> getHashCode) { this._equals = equals; this._getHashCode = getHashCode; } public bool Equals(T a, T b) { return _equals(a, b); } public int GetHashCode(T a) { if (_getHashCode != null) return _getHashCode(a); else return a.GetHashCode(); } }