C# 我们什么时候为字典做 GetHashCode() ?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1407380/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
When do we do GetHashCode() for a Dictionary?
提问by devnull
I have used Dictionary(TKey, TValue) for many purposes. But I haven't encountered any scenario to implement GetHashCode() which I believe is because my keys were of primary types like int and string. I am curious to know the scenarios (real world examples) when one should use a custom object for key and thus implement methods GetHashCode() Equals() etc.
我已经将 Dictionary(TKey, TValue) 用于多种目的。但是我还没有遇到任何实现 GetHashCode() 的场景,我认为这是因为我的键是主要类型,如 int 和 string。我很想知道当一个人应该使用自定义对象作为键并因此实现方法 GetHashCode() Equals() 等时的场景(现实世界的例子)。
And, does using a custom object for key necessitate implementing these functions?
而且,使用自定义对象作为键是否需要实现这些功能?
采纳答案by jason
You should override Equals
and GetHashCode
whenever the default Object.Equals
(tests for reference equality) will not suffice. This happens, for example, when the type of your key is a custom type and you want two keys to be considered equal even in cases when they are not the same instance of the custom type.
您应该覆盖Equals
并且GetHashCode
每当默认值Object.Equals
(测试引用相等性)不够时。例如,当您的键的类型是自定义类型并且您希望两个键被视为相等时,即使它们不是自定义类型的同一实例,也会发生这种情况。
For example, if your key is as simple as
例如,如果您的密钥很简单
class Point {
public int X { get; set; }
public int Y { get; set; }
}
and you want two Point
s two be considered equal if their X
s are equal and their Y
s are equal then you will need to override Equals
and GetHashCode
.
Point
如果它们的X
s 相等并且它们的Y
s 相等,则您希望两个s 两个被视为相等,那么您将需要覆盖Equals
and GetHashCode
。
回答by Andrew Hare
One example is when you need to create a composite key (that is a key comprised of more that one piece of data). That composite key would be a custom type that would need to override those methods.
一个例子是当您需要创建一个复合键(即由多个数据组成的键)时。该复合键将是需要覆盖这些方法的自定义类型。
For example, let's say that you had an in-memory cache of address records and you wanted to check to see if an address was in cache to save an expensive trip to the database to retrieve it. Let's also say that addresses are unique in terms of their street 1and zip codefields. You would implement your cache with something like this:
例如,假设您有一个地址记录的内存缓存,并且您想检查一个地址是否在缓存中,以节省昂贵的数据库之旅以检索它。假设地址在街道 1和邮政编码字段方面是唯一的。你会用这样的东西来实现你的缓存:
class AddressCacheKey
{
public String StreetOne { get; set; }
public String ZipCode { get; set; }
// overrides for Equals and GetHashCode
}
and
和
static Dictionary<AddressCacheKey,Address> cache;
Since your AddressCacheKey
type overrides the Equals
and GetHashCode
methods they would be a good candidate for a key in the dictionary and you would be able to determine whether or not you needed to take a trip to the database to retrieve a record based on more than one piece of data.
由于您的AddressCacheKey
类型覆盖了Equals
和GetHashCode
方法,因此它们将是字典中键的良好候选者,您将能够确定是否需要访问数据库以检索基于多条数据的记录.
回答by Alan
You have two questions here.
你在这里有两个问题。
- When do you need to implement GetHashCode()
- Would you ever use an object for a dictionary key.
- 什么时候需要实现 GetHashCode()
- 您会使用对象作为字典键吗?
Lets start with 1. If you are writing a class that might possibly be used by someone else, you will want to define GetHashCode() and Equals(), when reference Equals() is not enough. If you're not planning on using it in a dictionary, and it's for your own usage, then I see no reason to skip GetHashCode() etc.
让我们从 1 开始。如果您正在编写一个可能被其他人使用的类,当引用 Equals() 不够时,您将需要定义 GetHashCode() 和 Equals()。如果您不打算在字典中使用它,而且是供您自己使用,那么我认为没有理由跳过 GetHashCode() 等。
For 2), you should use an object anytime you have a need to have a constant time lookup from an object to some other type. Since GetHashCode() returns a numeric value, and collections store references, there is no penalty for using an Object over an Int or a string (remember a string is an object).
对于 2),您应该在需要从对象到其他类型进行恒定时间查找的任何时候使用对象。由于 GetHashCode() 返回一个数值,并且集合存储引用,因此在 Int 或字符串上使用 Object 不会受到惩罚(记住字符串是一个对象)。
回答by The Chairman
Just to make it clear: There is one important thing about Dictionary<TKey, TValue>
and GetHashCode()
: Dictionary uses GetHashCode to determine if two keys are equal i.e. if <TKey>
is of custom type you should care about implementing GetHashCode()
carefully. As Andrew Hare pointed out this is easy, if you have a simple type that identifies your custom object unambiguously. In case you have a combined identifier, it gets a little more complicated.
简单说一下:关于Dictionary<TKey, TValue>
and有一件重要的事情GetHashCode()
:Dictionary 使用 GetHashCode 来确定两个键是否相等,即如果<TKey>
是自定义类型,您应该小心实施GetHashCode()
。正如 Andrew Hare 指出的那样,这很容易,如果您有一个简单的类型,可以明确地标识您的自定义对象。如果你有一个组合标识符,它会变得更复杂一些。
As example consider a complex number as TKey
. A complex number is determined by its real and its imaginary part. Both are of simple type e.g. double
. But how would you identify if two complex numbers are equal? You implement GetHashCode()
for your custom complex type and combine both identifying parts.
例如,考虑一个复数为TKey
。复数由其实部和虚部决定。两者都是简单类型,例如double
. 但是你如何确定两个复数是否相等?您GetHashCode()
为自定义复杂类型实现并组合两个识别部分。
You find further reading on the latter here.
您可以在此处找到有关后者的进一步阅读。
UPDATE
更新
Based on Ergwun's comment I checked the behavior of Dictionary<TKey, TValue>.Add
with special respect to TKey
's implementation of Equals(object)
and GetHashCode()
. I
must confess that I was rather surprised by the results.
根据 Ergwun 的评论,我Dictionary<TKey, TValue>.Add
特别检查了和TKey
的实现。我必须承认,我对结果感到相当惊讶。Equals(object)
GetHashCode()
Given two objects k1
and k2
of type TKey
, two arbitrary objects v1
and v2
of type TValue
, and an empty dictionary d
of type Dictionary<TKey, TValue>
, this is what happens when adding v1
with key k1
to d
first and v2
with key k2
second (depending on the implementation of TKey.Equals(object)
and TKey.GetHashCode()
):
给定两个对象k1
和k2
type TKey
,两个任意对象v1
和v2
type TValue
,以及一个空字典d
type Dictionary<TKey, TValue>
,这就是将v1
key添加k1
到d
first 和v2
key k2
second时发生的情况(取决于TKey.Equals(object)
and的实现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
Conclusion: I was wrong as I originally thought the second case (where Equals
returns false
but both key objects have same hash code) would raise an ArgumentException
. But as the third case shows dictionary in some way does use GetHashCode()
. Anyway it seems to be good advice that two objects that are the same type and are equal must return the same hash code to ensure that instances Dictionary<TKey, TValue>
work correctly.
结论:我错了,因为我最初认为第二种情况(Equals
返回false
但两个关键对象具有相同的哈希码)会引发ArgumentException
. 但正如第三种情况所示,字典以某种方式使用GetHashCode()
. 无论如何,两个相同类型且相等的对象必须返回相同的哈希码以确保实例Dictionary<TKey, TValue>
正常工作似乎是个好建议。