我已将Dictionary(TKey,TValue)用于多种用途。但我没有遇到任何实现GetHashCode()的场景,我认为这是因为我的键是主要类型,如int和string。 我很想知道场景(真实世界的例子),当一个人应该使用自定义对象的键,从而实现方法GetHashCode()Equals()等。
而且,使用自定义对象作为密钥是否需要实现这些功能?
答案 0 :(得分:13)
每当默认Object.Equals
(参考相等测试)不够时,您应该覆盖Equals
和GetHashCode
。例如,当您的密钥类型是自定义类型并且您希望两个密钥被认为相等时,即使在它们不是自定义类型的同一实例的情况下,也会发生这种情况。
例如,如果您的密钥就像
一样简单class Point {
public int X { get; set; }
public int Y { get; set; }
}
如果Point
s相等并且X
s相等,则您希望两个Y
两个被视为相等,那么您需要覆盖Equals
和{ {1}}。
答案 1 :(得分:12)
只是要说清楚:Dictionary<TKey, TValue>
和GetHashCode()
有一个重要的事情:Dictionary使用GetHashCode来确定两个键是否相等,即如果<TKey>
是自定义类型,你应该关心谨慎实施GetHashCode()
。正如Andrew Hare指出这很容易,如果你有一个简单的类型,可以明确地识别你的自定义对象。如果你有一个组合标识符,它会变得更复杂。
例如,将复数视为TKey
。复数由它的真实及其虚部决定。两者都是简单类型,例如double
。但是你如何确定两个复数是否相等?您为自定义复杂类型实现GetHashode()
,并将两个识别部分组合在一起。
您可以进一步阅读后者here。
<强>更新强>
根据Ergwun的评论,我检查了Dictionary<TKey, TValue>.Add
的行为,特别尊重TKey
Equals(object)
和GetHashCode()
的实施情况。一世
我必须承认我对结果感到非常惊讶。
给定k1
类型k2
和TKey
的两个对象,v1
类型的两个任意对象v2
和TValue
,并为空类型为d
的字典Dictionary<TKey, TValue>
,这是首先将v1
添加到k1
d
到v2
,k2
添加密钥{{1}第二个(取决于TKey.Equals(object)
和TKey.GetHashCode()
的实现):
k1.Equals(k2) k1.GetHashCode() == k2.GetHashCode() d.Add(k2, v2)
false false ok
false true ok
true false ok
true true System.ArgumentException
结论:我错了,因为我最初认为第二种情况(Equals
返回false
,但两个关键对象都有相同的哈希码)会引发ArgumentException
。但是,由于第三种情况以某种方式显示字典确实使用GetHashCode()
。无论如何,两个相同类型且相同的对象必须返回相同的哈希码以确保实例Dictionary<TKey, TValue>
正常工作,这似乎是一个好建议。
答案 2 :(得分:2)
一个例子是当你需要创建一个复合键(这是一个由多个数据组成的键)。该组合键将是一个需要覆盖这些方法的自定义类型。
例如,假设您有一个内存中的地址记录缓存,并且您想检查地址是否在缓存中以节省昂贵的数据库访问以检索它。我们还要说地址在 street 1 和邮政编码字段方面是唯一的。您可以使用以下内容实现缓存:
class AddressCacheKey
{
public String StreetOne { get; set; }
public String ZipCode { get; set; }
// overrides for Equals and GetHashCode
}
和
static Dictionary<AddressCacheKey,Address> cache;
由于您的AddressCacheKey
类型会覆盖Equals
和GetHashCode
方法,因此它们可能是字典中某个键的理想选择,您可以确定是否需要前往数据库,根据多个数据检索记录。
答案 3 :(得分:1)
这里有两个问题。
让我们从1开始。如果你正在编写一个可能被其他人使用的类,那么当引用Equals()不够时,你将需要定义GetHashCode()和Equals()。如果您不打算在字典中使用它,并且它是为了您自己的用法,那么我认为没有理由跳过GetHashCode()等。
对于2),您应该在需要从对象到其他类型的常量时间查找时使用对象。由于GetHashCode()返回一个数值,并且集合存储引用,因此在Int或字符串上使用Object没有任何代价(请记住字符串是一个对象)。