Reputation: 12505
It seems I cannot understand the documentation of Hashcode struct:
I tried a naive:
public struct S : IEquatable<S>
{
public int I { get; set; }
public string[] A { get; set; }
public override bool Equals(object? obj) => obj is S s && Equals(s);
public bool Equals(S other) => I == other.I && StructuralComparisons.StructuralEqualityComparer.Equals(A, other.A);
// public override int GetHashCode() => I.GetHashCode() ^ StructuralComparisons.StructuralEqualityComparer.GetHashCode(A);
public override int GetHashCode() => HashCode.Combine(I, A);
}
Which lead to:
S s1 = new S() { I = 42, A = new string[] { "hello" } };
S s2 = new S() { I = 42, A = new string[] { "hello" } };
Assert.Equal(s1.GetHashCode(), s2.GetHashCode());
Giving an error:
Xunit.Sdk.EqualException: 'Assert.Equal() Failure Expected: 840823323 Actual: -1160370390'
What is the right way to use HashCode.Combine
(I did not like my earlier XOR solution) ?
Upvotes: 0
Views: 1131
Reputation: 152566
You're using HashCode.Combine
correctly. The problem is that you're using StructuralEqualityComparer
for the equality comparison but not for the hash code generation, so the two strings arrays are "equal" but do not generate the same hash code by default. Use
public override int GetHashCode() => HashCode.Combine(I,
StructuralComparisons.StructuralEqualityComparer.GetHashCode(A));
This is necessary because Combine
will call GetHashCode
on each instance, which for lists will be different regardless of the values in the list. So you need to specify how you want to generate the hash code.
Upvotes: 2