using System;
using System.Collections.Generic;
using System.Diagnostics;
internal sealed class MyItem
{
public MyItem(int number, string text) {
Number = number;
Text = text ?? String.Empty;
}
public int Number { get; private set; }
public string Text { get; private set; }
}
internal sealed class MyItemComparer : EqualityComparer<MyItem>
{
public override bool Equals(MyItem x, MyItem y) {
if(x == null) {
return y == null;
} else if(y == null) {
return false;
} else {
return EqualityComparer<int>.Default.Equals(x.Number, y.Number);
}//if
}
public override int GetHashCode(MyItem obj) {
if(obj == null) {
return 0;
}//if
return EqualityComparer<int>.Default.GetHashCode(obj.Number);
}
}
internal static class Program
{
private static void Main() {
var itemComparer = new MyItemComparer();
var set1 = new HashSet<MyItem>(itemComparer) { new MyItem(1, "One"), };
var set2 = new HashSet<MyItem>(itemComparer) { new MyItem(1, "1"), };
var test = set1.SetEquals(set2);
Debug.Assert(test); // OK
var setComparer = HashSet<MyItem>.CreateSetComparer();
var equals = setComparer.Equals(set1, set2);
Debug.Assert(equals); // OK
var hash1 = setComparer.GetHashCode(set1);
var hash2 = setComparer.GetHashCode(set2);
Debug.Assert(hash1 == hash2, "hash1 == hash2"); // Failed
}
}
Ошибка заключается в том, что для двух объектов, которые компаратор считает равными, он возвращает различные хеш-коды. Происходит это в рассмотренном случае из-за того, что при рассчёте равенства используется внутренний компаратор хеш-сета (потому что компараторы оказываются равными), а вот при подсчёте хеш-кода всегда используется дефолтовый компаратор.
Для решения моей проблемы будет достаточным написать свой аналог компаратора, в который можно будет передать кастомный компаратор элементов.
Update: Желающие могут проголосовать за этот баг на коннекте.