如果我的班级实现GetHashCode
,我应该实施非通用Equals
和IEqualityComparer<T>
吗?
更新
我希望MS在他们介绍IEqualityComparer<T>
时更新了他们收藏的实施。所以我认为Dictionary
和任何其他集合类将在内部检查我的类是否实现IEqualityComparer<T>
并且仅在未实现该接口时才使用通用方法GetHashCode
和Equals
。没有集合支持,该接口几乎没有价值。
UPDATE2:
我刚刚使用ILSpy检查了Dictionary.FindEntry(TKey key)
。它使用IEqualityComparer<TKey>
(下面的变量comparer
)。事实上,我根本没有找到任何非通用GetHashCode
和Equals
函数的使用。
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;
}
}
所以我的班级似乎只需实施IEqualityComparer<T>
即可与Dictionary
正确使用。
据我所知,为了以防万一,实现非通用函数是没有害处的。
但是,如果它没有带来任何价值,我们应该花时间吗?
我会更具体地提出我的问题:
如果我的类实现GetHashCode
并且:
Equals
和IEqualityComparer<T>
GetHashCode
和Equals
方法。Microsoft代码是否仍需要非通用版本才能正常工作?
UPDATE3 :
我想我明白了。我认为IEqualityComparer<T>
将在我的班级内实施。在这种情况下,我们将在一个地方拥有通用版本而非通用版本的方法。
这不是应该使用IEqualityComparer<T>
的方式。它应该作为单独的类实现并用作参数。
感谢大家。
答案 0 :(得分:3)
这取决于。 IEqualityComparer<T>
用于比较类型T
的两个实例 - 通常由单独的比较器类实现。通常,您不会在类类型T
中实现此功能。它旨在提供替代比较,以便与支持他的类型一起使用。
如果您在课程本身中实现此功能,则通常会实施IEquatable<T>
。
话虽如此,覆盖Object.Equals
通常很有用,这通常非常简单,因为您可以使用IEquatable<T>.Equals
方法来实现Object.Equals
。这使得它“实施起来”成本低廉。由于可以使用Object.Equals
,它将为相等提供一致的含义,因此实现它通常是一个好主意。
如果您的对象将用作哈希中的键,例如Dictionary<T,U>
或HashSet<T>
,则应覆盖GetHashCode
。如果甚至有可能以这种方式使用它,那么重写这种方法是有益的。通常情况下,我发现在我实现相等的情况下覆盖GetHashCode
是有用的,以防万一我稍后将该类型用作键。
答案 1 :(得分:2)
IEqualityComparer旨在替换每个.NET对象已有的GetHashCode和Equals的默认实现。此接口仅由字典和(散列)集使用,以使用不同的散列和比较方案作为默认使用的对象。
如果您的对象在Dictionaries和HashTables中用作键,则应首先覆盖Equals和GetHashCode,让Sets / Dictionaries使用默认的比较器(您称之为EqualityComparere.Default的对象)为您的对象调用Equals和GetHashCode无论如何你的对象。
通过IEqualityComparer提供外部比较器的唯一原因是使用不同的比较方案。例如。对于字符串,您可以选择区分大小写和不区分大小写的变体之间的BCL StringComparer类。
<强> UPDATE1 强>
此问题的目的是为什么List和其他集合始终使用默认比较器而不是对象提供的比较器。如果一个对象确实实现了Equals和GetHashCode,那么为什么如果对象同时执行IEqualityComparer,List不会使用它们?由于List不提供允许使用不同比较器的ctor,因此它需要使用默认的比较器。
但是如果你想使用不同的LINQ,你总是可以使用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);
答案 2 :(得分:1)
如果我理解正确并且你问如果你实施IEqualityComparer
是否还必须实施IEqualityComparer<T>
,那么答案就是你不必,但这可能是一个好主意。它只会使您的比较器与现有代码更兼容。