I have a LINQ Distinct() statement that uses my own custom comparer, like this:
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>());
This is all fine and dandy and works as I want. Out of curiosity, do I need to define my own Comparer, or can I replace it with a delegate? I thought I should be able to do something like this:
var distincts = bundle.GetAllThings.Distinct((a,b) => a.Id == b.Id);
But this doesn't compile. Is there a neat trick?
Distinct takes an IEqualityComparer as the second argument, so you will need an IEqualityComparer. It's not too hard to make a generic one that will take a delegate, though. Of course, this has probably already been implemented in some places, such as MoreLINQ suggested in one of the other answers.
You could implement it something like this:
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();
}
}
}
Which gives you the syntax:
source.DistinctBy(a => a.Id);
Or, if you feel it's clearer this way:
source.Distinct(Compare.By(a => a.Id));