I'm trying to do a Linq GroupBy on some objects using an explicit key type. I'm not passing an IEqualityComparer
to the GroupBy, so according to the docs:
The default equality comparer
Default
is used to compare keys.
It explains the EqualityComparer<T>.Default
property like this:
The
Default
property checks whether typeT
implements theSystem.IEquatable<T>
generic interface and if so returns anEqualityComparer<T>
that uses that implementation.
In the code below, I'm grouping an array of Fred
objects. They have a key type called FredKey
, which implements IEquatable<FredKey>
.
That should be enough to make the grouping work, but the grouping is not working. In the last line below I should have 2 groups, but I don't, I just have 3 groups containing the 3 input items.
Why is the grouping not working?
class Fred
{
public string A;
public string B;
public FredKey Key
{
get { return new FredKey() { A = this.A }; }
}
}
class FredKey : IEquatable<FredKey>
{
public string A;
public bool Equals(FredKey other)
{
return A == other.A;
}
}
class Program
{
static void Main(string[] args)
{
var f = new Fred[]
{
new Fred {A = "hello", B = "frog"},
new Fred {A = "jim", B = "jog"},
new Fred {A = "hello", B = "bog"},
};
var groups = f.GroupBy(x => x.Key);
Debug.Assert(groups.Count() == 2); // <--- fails
}
}
From MSDN
If you implement IEquatable, you should also override the base class implementations of Object::Equals(Object) and GetHashCode() so that their behavior is consistent with that of the IEquatable::Equals method. If you do override Object::Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. This ensures that all invocations of the Equals() method return consistent results.
add this to FredKey and it should work
public override int GetHashCode()
{
return A.GetHashCode();
}
Here is a complete example with a Fiddle. Note: the example differs slightly from the question's example.
The following implementation of IEquatable
can act as the TKey
in GroupBy
. Note that it includes both GetHashCode
and Equals
.
public class CustomKey : IEquatable<CustomKey>
{
public string A { get; set; }
public string B { get; set; }
public bool Equals(CustomKey other)
{
return other.A == A && other.B == B;
}
public override int GetHashCode()
{
return string.Format("{0}{1}", A, B).GetHashCode();
}
}
public class Custom
{
public string A { get; set; }
public string B { get; set; }
public string C { get; set; }
}
public static void Main()
{
var c = new Custom[]
{
new Custom {A = "hello", B = "frog" },
new Custom {A = "jim", B = "jog" },
new Custom {A = "hello", B = "frog" },
};
var groups = c.GroupBy(x => new CustomKey { A = x.A, B = x.B } );
Console.WriteLine(groups.Count() == 2);
}
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