Have a read through K. Scott Allen's excellent post here:
And Equality for All ... Anonymous Types
The short answer (and I quote):
Turns out the C# compiler overrides Equals and GetHashCode for anonymous types. The implementation of the two overridden methods uses all the public properties on the type to compute an object's hash code and test for equality. If two objects of the same anonymous type have all the same values for their properties – the objects are equal.
So it's totally safe to use the Distinct() method on a query that returns anonymous types.
public class DelegateComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _equals;
private Func<T, int> _hashCode;
public DelegateComparer(Func<T, T, bool> equals, Func<T, int> hashCode)
{
_equals= equals;
_hashCode = hashCode;
}
public bool Equals(T x, T y)
{
return _equals(x, y);
}
public int GetHashCode(T obj)
{
if(_hashCode!=null)
return _hashCode(obj);
return obj.GetHashCode();
}
}
public static class Extensions
{
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items,
Func<T, T, bool> equals, Func<T,int> hashCode)
{
return items.Distinct(new DelegateComparer<T>(equals, hashCode));
}
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items,
Func<T, T, bool> equals)
{
return items.Distinct(new DelegateComparer<T>(equals,null));
}
}
var uniqueItems=students.Select(s=> new {FirstName=s.FirstName, LastName=s.LastName})
.Distinct((a,b) => a.FirstName==b.FirstName, c => c.FirstName.GetHashCode()).ToList();
Sorry for the messed up formatting earlier
Interesting that it works in C# but not in VB
Returns the 26 letters:
var MyBet = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ";
MyBet.ToCharArray()
.Select(x => new {lower = x.ToString().ToLower(), upper = x.ToString().ToUpper()})
.Distinct()
.Dump();
Returns 52...
Dim MyBet = "aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ"
MyBet.ToCharArray() _
.Select(Function(x) New With {.lower = x.ToString.ToLower(), .upper = x.ToString.ToUpper()}) _
.Distinct() _
.Dump()
I ran a little test and found that if the properties are value types, it seems to work ok. If they are not value types, then the type needs provide it's own Equals and GetHashCode implementations for it to work. Strings, I would think, would work.
You can create your own Distinct Extension method which takes lambda expression. Here's an example
Create a class which derives from IEqualityComparer interface
public class DelegateComparer<T> : IEqualityComparer<T>
{
private Func<T, T, bool> _equals;
private Func<T, int> _hashCode;
public DelegateComparer(Func<T, T, bool> equals, Func<T, int> hashCode)
{
_equals= equals;
_hashCode = hashCode;
}
public bool Equals(T x, T y)
{
return _equals(x, y);
}
public int GetHashCode(T obj)
{
if(_hashCode!=null)
return _hashCode(obj);
return obj.GetHashCode();
}
}
Then create your Distinct Extension method
public static class Extensions
{
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items,
Func<T, T, bool> equals, Func<T,int> hashCode)
{
return items.Distinct(new DelegateComparer<T>(equals, hashCode));
}
public static IEnumerable<T> Distinct<T>(this IEnumerable<T> items,
Func<T, T, bool> equals)
{
return items.Distinct(new DelegateComparer<T>(equals,null));
}
}
and you can use this method find distinct items
var uniqueItems=students.Select(s=> new {FirstName=s.FirstName, LastName=s.LastName})
.Distinct((a,b) => a.FirstName==b.FirstName, c => c.FirstName.GetHashCode()).ToList();
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With