At long last, with the generics, lambdas and LINQ, C# is finally worth using. A bit restrictive at times, but OK.
č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 {
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)(new DogsWithTheSameArticle()));
OK. It works. But it's long and ugly, ugly, ugly.
Let us hide the insanity!
private class LambdaEqualityComparer : IEqualityComparer {
private Func _comparer;
public LambdaEqualityComparer(Func comparer) {
_comparer = comparer;
}
public bool Equals(T obj1, T obj2) {
return _comparer(obj1, obj2);
}
public int GetHashCode(T obj) {
return 0;
}
}
private class LambdaEqualityComparer : IEqualityComparer {
private Func _comparer;
private Func _selector;
public LambdaEqualityComparer(Func 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();
}
}
///
/// Filters the enumerable to contain only distinct elements using a custom comparator.
///
/// a lambda that returns true if the two objects are to be considered equal
public static IEnumerable Distinct(this IEnumerable list, Func comparator) {
return list.Distinct(new LambdaEqualityComparer(comparator));
}
///
/// Filters the enumerable to contain only distinct elements using a custom comparator.
///
/// a lambda that extracts the value(s) to compare. If the selected values are equal, the objects are considered duplicate
public static IEnumerable Distinct(this IEnumerable list, Func selector) where TElem : IComparable {
return list.Distinct(new LambdaEqualityComparer(selector));
}
Přihlásit se k odběru:
Příspěvky (Atom)