čtvrtek 4. srpna 2011

enumerable.Distinct(IEqualityComparer what???

Now I understand years ago when there were no lambdas in C# and the syntax for function references (delegates for the C# folk) was so convoluted that they were almost unusable ... at those dark times all those IEqualityComparers and loads of other interfaces made some sense but now? All I want is to filter some enumerable to get only the distinct values where distinct means the .ArticleId property is different (other properties either depend on ArticleId or are irrelevant and will not be used when processing the filtered list). Should be simple right? I expected something like var filtered = list.Distinct( (obj1, obj2) => obj1.ArticleId == obj2.ArticleId ); or even (as the ArticleId is a plain old int) var filtered = list.Distinct( obj => obj.ArticleId ); Too simple. ... private class DogsWithTheSameArticle : IEqualityComparer<WatchDogsToSend> { public bool Equals(WatchDogsToSend dog1, WatchDogsToSend dog2) { return dog1.ArticleId == dog2.ArticleId; } public int GetHashCode(WatchDogsToSend dog) { return dog.GetHashCode(); } } ... ... many a line away ... ... var filtered = notification.Distinct((IEqualityComparer<WatchDogsToSend>)(new DogsWithTheSameArticle())); OK. It works. But it's long and ugly, ugly, ugly. Let us hide the insanity! private class LambdaEqualityComparer<T> : IEqualityComparer<T> { private Func<T, T, bool> _comparer; public LambdaEqualityComparer(Func<T, T, bool> comparer) { _comparer = comparer; } public bool Equals(T obj1, T obj2) { return _comparer(obj1, obj2); } public int GetHashCode(T obj) { return 0; } } private class LambdaEqualityComparer<T,M> : IEqualityComparer<T> { private Func<T, T, bool> _comparer; private Func<T, M> _selector; public LambdaEqualityComparer(Func<T, M> selector) { _selector = selector; _comparer = (obj1, obj2) => Object.ReferenceEquals(obj1, obj2) || obj1 != null && obj2 != null && selector(obj1).Equals(selector(obj2)); } public bool Equals(T obj1, T obj2) { return _comparer(obj1, obj2); } public int GetHashCode(T obj) { return _selector(obj).GetHashCode(); } } /// <summary> /// Filters the enumerable to contain only distinct elements using a custom comparator. /// </summary> /// <param name="comparator">a lambda that returns true if the two objects are to be considered equal</param> public static IEnumerable<T> Distinct<T>(this IEnumerable<T> list, Func<T, T, bool> comparator) { return list.Distinct(new LambdaEqualityComparer<T>(comparator)); } /// <summary> /// Filters the enumerable to contain only distinct elements using a custom comparator. /// </summary> /// <param name="comparator">a lambda that extracts the value(s) to compare. If the selected values are equal, the objects are considered duplicate</param> public static IEnumerable<T> Distinct<T, TElem>(this IEnumerable<T> list, Func<T, TElem> selector) where TElem : IComparable { return list.Distinct(new LambdaEqualityComparer<T, TElem>(selector)); }

Žádné komentáře:

Okomentovat