Я столкнулся с этой проблемой при написании векторного класса. Я хотел сравнить векторы на равенство, но операции с плавающей точкой дают ошибки округления, поэтому я хотел приблизительное равенство. Короче говоря, переопределение equals - плохая идея, если ваша реализация не симметрична, рефлексивна и транзитивна.
Другие классы будут предполагать, что equals имеет эти свойства, так же как и классы, использующие эти классы, и поэтому вы можете оказаться в странных случаях. Например, список может обеспечивать уникальность, но в итоге получится два элемента, которые оцениваются как равные некоторому элементу B.
Хеш-таблица является идеальным примером непредсказуемого поведения, когда вы нарушаете равенство. Например:
//Assume a == b, b == c, but a != c
var T = new Dictionary<YourType, int>()
T[a] = 0
T[c] = 1
return T[b] //0 or 1? who knows!
Другим примером будет Set:
//Assume a == b, b == c, but a != c
var T = new HashSet<YourType>()
T.Add(a)
T.Add(c)
if (T.contains(b)) then T.remove(b)
//surely T can't contain b anymore! I sure hope no one breaks the properties of equality!
if (T.contains(b)) then throw new Exception()
Я предлагаю использовать другой метод с именем, подобным ApproxEquals. Вы можете также рассмотреть возможность переопределения оператора ==, потому что он не является виртуальным и, следовательно, не будет случайно использоваться другими классами, такими как Equals.
Если вы действительно не можете использовать равенство ссылок для хеш-таблицы, не ухудшайте производительность в тех случаях, когда это возможно. Добавьте интерфейс IApproxEquals, внедрите его в свой класс и добавьте метод расширения GetApprox в словарь, который перечисляет ключи, которые ищут приблизительно равный, и возвращает соответствующее значение. Вы также можете написать собственный словарь, особенно для трехмерных векторов, или что вам нужно.