2

Should I implement non-generic GetHashCode and Equals if my class implements IEqualityComparer<T>?

Update: My hope was that MS updated implementation of their collection when they introduced IEqualityComparer<T>. So I thought that Dictionary and any other collection classes will check internally if my class implements IEqualityComparer<T> and use not generic methods GetHashCode and Equals only if that interface is not implemented. Without collections support that interface has very little value.

Update2: I just checked Dictionary.FindEntry(TKey key) using ILSpy. It uses IEqualityComparer<TKey> (varriable comparer below). In fact I did not find any using of not generic GetHashCode and Equals functions at all.

int num = this.comparer.GetHashCode(key) & 2147483647;
for (int i = this.buckets[num % this.buckets.Length]; i >= 0; i = this.entries[i].next)
{
    if (this.entries[i].hashCode == num
                && this.comparer.Equals(this.entries[i].key, key))
    {
        return i;
    }
}

So it seems to that my class only needs to implement IEqualityComparer<T> to be properly used with Dictionary.

I understand that there will be no harm to implement not generic functions just in case.

But should we spend time if it brings no value?

I will make my question more specific:

Should I implement non-generic GetHashCode and Equals if my class implements IEqualityComparer<T> and:

  1. I do not use not generic collections in my code
  2. Third party code does not call GetHashCode and Equals methods of my code.

Does Microsoft code still needs non generic versions to work properly?

Update3: I think I got it. I thought that IEqualityComparer<T> is to be implemented inside my class. In that case we would have generic and not generic versions of methods in one place. That is not how IEqualityComparer<T> should be used. It should be implemented as separate class and used as parameter.

Thanks to everybody.

4

3 回答 3

3

这取决于。 IEqualityComparer<T>用于比较一个类型的两个实例T- 通常由单独的比较器类实现。通常你不会在类 type 中实现它T。它旨在为支持他的类型提供替代比较。

如果您在类本身中实现这一点,您通常会实现IEquatable<T>.

话虽如此,覆盖通常很有用Object.Equals,这通常非常简单,因为您可以使用该IEquatable<T>.Equals方法来实现Object.Equals. 这使其实施起来“便宜”。正如Object.Equals可以使用的那样,它将为相等提供一致的含义,因此通常实现它是一个好主意。

如果您的对象将用作散列中的键,例如 aDictionary<T,U>或 a HashSet<T>,那么您应该覆盖GetHashCode。如果甚至有可能以这种方式使用它,那么覆盖此方法是有益的。通常,我发现在GetHashCode我实现相等的任何时候重写都是有用的,以防我稍后将类型用作键。

于 2012-06-09T19:30:58.050 回答
2

IEqualityComparer 旨在替换每个 .NET 对象已经拥有的 GetHashCode 和 Equals 的默认实现。此接口仅由字典和 (Hash)Sets 使用,以使用与对象默认使用的不同的散列和比较方案。

如果您的对象在字典和哈希表中用作键,您应该首先覆盖 Equals 和 GetHashCode 以让 Sets/Dictionaries 为您的对象使用默认比较器(您称为 EqualityComparere.Default 的比较器),该比较器确实调用您的对象的 Equals 和 GetHashCode反正。

通过 IEqualityComparer 提供外部比较器的唯一原因是使用不同的比较方案。例如,对于字符串,您可以在区分大小写和不区分大小写的变体之间从 BCL StringComparer类中进行选择。

更新1

这个问题的目的是为什么 List 和其他集合总是使用默认比较器而不是对象提供的比较器。如果一个对象已经实现了 Equals 和 GetHashCode,如果对象同时实现了 IEqualityComparer,为什么 List 不使用它们?由于 List 不提供允许使用不同比较器的 ctor,因此它确实需要使用默认比较器。

但是如果你想使用不同的方法,你总是可以使用 LINQ,它允许你明确地传递你自己的比较器来解决这个问题。例如Enumerable.Contains有一个重载,您可以在其中传入您自己的比较器。

来自 MSDN 示例:

Product[] fruits = { new Product { Name = "apple", Code = 9 }, 
                       new Product { Name = "orange", Code = 4 }, 
                       new Product { Name = "lemon", Code = 12 } };

Product apple = new Product { Name = "apple", Code = 9 };
Product kiwi = new Product {Name = "kiwi", Code = 8 };

ProductComparer prodc = new ProductComparer();

bool hasApple = fruits.Contains(apple, prodc);
bool hasKiwi = fruits.Contains(kiwi, prodc);
于 2012-06-09T19:33:15.817 回答
1

如果我对您的理解正确,并且您问是否还必须实现IEqualityComparer如果您实施IEqualityComparer<T>,那么答案是您不必这样做,但这可能是一个好主意。它只会使您的比较器与现有代码更兼容。

于 2012-06-09T19:33:28.910 回答