为什么在重写Equals方法时重写GetHashCode很重要?

时间:2021-04-01 16:50:24

Given the following class

鉴于以下课程

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Which is preferred?

        return base.GetHashCode();

        //return this.FooId.GetHashCode();
    }
}

I have overridden the Equals method because Foo represent a row for the Foos table. Which is the preferred method for overriding the GetHashCode?

我已经重写了Equals方法,因为Foo代表Foos表的一行。哪个是覆盖GetHashCode的首选方法?

Why is it important to override GetHashCode?

为什么重写GetHashCode很重要?

12 个解决方案

#1


1157  

Yes, it is important if your item will be used as a key in a dictionary, or HashSet<T>, etc - since this is used (in the absence of a custom IEqualityComparer<T>) to group items into buckets. If the hash-code for two items does not match, they may never be considered equal (Equals will simply never be called).

是的,重要的是如果您的项目将用作字典中的键或HashSet 等 - 因为这是使用(在没有自定义IEqualityComparer 的情况下)将项目分组到存储桶中。如果两个项的哈希码不匹配,它们可能永远不会被认为是相等的(Equals将永远不会被调用)。

The GetHashCode() method should reflect the Equals logic; the rules are:

GetHashCode()方法应该反映Equals逻辑;规则是:

  • if two things are equal (Equals(...) == true) then they must return the same value for GetHashCode()
  • 如果两个东西相等(Equals(...)== true)那么它们必须为GetHashCode()返回相同的值

  • if the GetHashCode() is equal, it is not necessary for them to be the same; this is a collision, and Equals will be called to see if it is a real equality or not.
  • 如果GetHashCode()相等,则它们不必相同;这是一个碰撞,并且将调用Equals以查看它是否是真正的平等。

In this case, it looks like "return FooId;" is a suitable GetHashCode() implementation. If you are testing multiple properties, it is common to combine them using code like below, to reduce diagonal collisions (i.e. so that new Foo(3,5) has a different hash-code to new Foo(5,3)):

在这种情况下,它看起来像“返回FooId;”是一个合适的GetHashCode()实现。如果您正在测试多个属性,通常使用如下代码组合它们,以减少对角线冲突(即,使新Foo(3,5)具有与新Foo(5,3)不同的哈希码):

int hash = 13;
hash = (hash * 7) + field1.GetHashCode();
hash = (hash * 7) + field2.GetHashCode();
...
return hash;

Oh - for convenience, you might also consider providing == and != operators when overriding Equals and GetHashCode.

哦 - 为方便起见,在覆盖Equals和GetHashCode时,您可能还会考虑提供==和!=运算符。


A demonstration of what happens when you get this wrong is here.

当你弄错了会发生什么事的证明就在这里。

#2


125  

It's actually very hard to implement GetHashCode() correctly because, in addition to the rules Marc already mentioned, the hash code should not change during the lifetime of an object. Therefore the fields which are used to calculate the hash code must be immutable.

实际上很难正确实现GetHashCode(),因为除了Marc已经提到的规则之外,哈希代码在对象的生命周期内不应该改变。因此,用于计算哈希码的字段必须是不可变的。

I finally found a solution to this problem when I was working with NHibernate. My approach is to calculate the hash code from the ID of the object. The ID can only be set though the constructor so if you want to change the ID, which is very unlikely, you have to create a new object which has a new ID and therefore a new hash code. This approach works best with GUIDs because you can provide a parameterless constructor which randomly generates an ID.

当我使用NHibernate时,我终于找到了解决这个问题的方法。我的方法是根据对象的ID计算哈希码。只能通过构造函数设置ID,因此如果要更改ID,这是非常不可能的,您必须创建一个具有新ID的新对象,因此需要新的哈希代码。这种方法最适用于GUID,因为您可以提供随机生成ID的无参数构造函数。

#3


46  

By overriding Equals you're basically stating that you are the one who knows better how to compare two instances of a given type, so you're likely to be the best candidate to provide the best hash code.

通过重写Equals,您基本上声明自己是更了解如何比较给定类型的两个实例的人,因此您可能是提供最佳哈希码的最佳候选者。

This is an example of how ReSharper writes a GetHashCode() function for you:

这是ReSharper如何为您编写GetHashCode()函数的示例:

public override int GetHashCode()
{
    unchecked
    {
        var result = 0;
        result = (result * 397) ^ m_someVar1;
        result = (result * 397) ^ m_someVar2;
        result = (result * 397) ^ m_someVar3;
        result = (result * 397) ^ m_someVar4;
        return result;
    }
}

As you can see it just tries to guess a good hash code based on all the fields in the class, but since you know your object's domain or value ranges you could still provide a better one.

正如您所看到的,它只是尝试根据类中的所有字段来猜测一个好的哈希代码,但由于您知道对象的域或值范围,因此您仍然可以提供更好的哈希代码。

#4


34  

Please don´t forget to check the obj parameter against null when overriding Equals(). And also compare the type.

在重写Equals()时,请不要忘记检查obj参数是否为null。并且还比较类型。

public override bool Equals(object obj)
{
    if (obj == null || GetType() != obj.GetType())
        return false;

    Foo fooItem = obj as Foo;

    return fooItem.FooId == this.FooId;
}

The reason for this is: Equals must return false on comparison to null. See also http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

原因是:与null相比,Equals必须返回false。另请参见http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

#5


26  

How about:

public override int GetHashCode()
{
    return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}

Assuming performance is not an issue :)

假设性能不是问题:)

#6


9  

It is because the framework requires that two objects that are the same must have the same hashcode. If you override the equals method to do a special comparison of two objects and the two objects are considered the same by the method, then the hash code of the two objects must also be the same. (Dictionaries and Hashtables rely on this principle).

这是因为框架要求两个相同的对象必须具有相同的哈希码。如果重写equals方法以对两个对象进行特殊比较,并且方法认为两个对象相同,则两个对象的哈希码也必须相同。 (字典和Hashtables依赖于这个原则)。

#7


9  

Just to add on above answers:

只是添加以上答案:

If you don't override Equals then the default behavior is that references of the objects are compared. The same applies to hashcode - the default implmentation is typically based on a memory address of the reference. Because you did override Equals it means the correct behavior is to compare whatever you implemented on Equals and not the references, so you should do the same for the hashcode.

如果不重写等于,则默认行为是比较对象的引用。这同样适用于hashcode - 默认的implmentation通常基于引用的内存地址。因为你确实覆盖了Equals,所以它意味着正确的行为是比较你在Equals而不是引用上实现的任何东西,所以你应该对hashcode做同样的事情。

Clients of your class will expect the hashcode to have similar logic to the equals method, for example linq methods which use a IEqualityComparer first compare the hashcodes and only if they're equal they'll compare the Equals() method which might be more expensive to run, if we didn't implement hashcode, equal object will probably have different hashcodes (because they have different memory address) and will be determined wrongly as not equal (Equals() won't even hit).

您的类的客户端将期望哈希码具有与equals方法类似的逻辑,例如使用IEqualityComparer的linq方法首先比较哈希码,并且只有当它们相等时它们才会比较可能更昂贵的Equals()方法如果我们没有实现hashcode,那么equ对象可能会有不同的hashcode(因为它们有不同的内存地址),并且会被错误地判断为不相等(Equals()甚至不会命中)。

In addition, except the problem that you might not be able to find your object if you used it in a dictionary (because it was inserted by one hashcode and when you look for it the default hashcode will probably be different and again the Equals() won't even be called, like Marc Gravell explains in his answer, you also introduce a violation of the dictionary or hashset concept which should not allow identical keys - you already declared that those objects are essentially the same when you overrode Equals so you don't want both of them as different keys on a data structure which suppose to have a unique key. But because they have a different hashcode the "same" key will be inserted as different one.

此外,除了您在字典中使用它时可能无法找到对象的问题(因为它是由一个哈希码插入的,当您查找它时,默认哈希码可能会有所不同,而且Equals()甚至不会被调用,就像Marc Gravell在他的回答中解释的那样,你也引入了违反字典或hashset概念的行为,它不应该允许相同的键 - 你已经声明当你覆盖Equals时这些对象基本相同所以你不要不希望它们都是数据结构上的不同键,它们假设有一个唯一键。但是因为它们有不同的哈希码,所以“相同”键将作为不同的键插入。

#8


8  

We have two problems to cope with.

我们有两个问题需要解决。

  1. You cannot provide a sensible GetHashCode() if any field in the object can be changed. Also often a object will NEVER be used in a collection that depends on GetHashCode(). So the cost of implementing GetHashCode() is often not worth it, or it is not possible.

    如果可以更改对象中的任何字段,则无法提供合理的GetHashCode()。通常,对象永远不会在依赖于GetHashCode()的集合中使用。因此,实现GetHashCode()的成本通常是不值得的,或者是不可能的。

  2. If someone puts your object in a collection that calls GetHashCode() and you have overrided Equals() without also making GetHashCode() behave in a correct way, that person may spend days tracking down the problem.

    如果有人将您的对象放入一个调用GetHashCode()的集合中并且您已经覆盖了Equals()而没有使GetHashCode()以正确的方式运行,那么该人可能需要花费数天时间来追踪问题。

Therefore by default I do.

因此默认情况下我这样做。

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Some comment to explain if there is a real problem with providing GetHashCode() 
        // or if I just don't see a need for it for the given class
        throw new Exception("Sorry I don't know what GetHashCode should do for this class");
    }
}

#9


5  

Hash code is used for hash-based collections like Dictionary, Hashtable, HashSet etc. The purpose of this code is to very quickly pre-sort specific object by putting it into specific group (bucket). This pre-sorting helps tremendously in finding this object when you need to retrieve it back from hash-collection because code has to search for your object in just one bucket instead of in all objects it contains. The better distribution of hash codes (better uniqueness) the faster retrieval. In ideal situation where each object has a unique hash code, finding it is an O(1) operation. In most cases it approaches O(1).

散列代码用于基于散列的集合,如Dictionary,Hashtable,HashSet等。此代码的目的是通过将特定对象放入特定组(存储桶)来非常快速地对其进行预排序。当您需要从哈希集合中检索此对象时,这种预排序有助于查找此对象,因为代码必须仅在一个存储桶中搜索您的对象,而不是在其包含的所有对象中搜索对象。哈希码的更好分布(更好的唯一性)更快的检索。在每个对象具有唯一哈希码的理想情况下,找到它是O(1)操作。在大多数情况下,它接近O(1)。

#10


4  

It's not necessarily important; it depends on the size of your collections and your performance requirements and whether your class will be used in a library where you may not know the performance requirements. I frequently know my collection sizes are not very large and my time is more valuable than a few microseconds of performance gained by creating a perfect hash code; so (to get rid of the annoying warning by the compiler) I simply use:

它不一定重要;这取决于您的集合的大小和您的性能要求,以及您的类是否将用于您可能不知道性能要求的库中。我经常知道我的集合大小不是很大,而且我的时间比通过创建完美的哈希码获得的几微秒的性能更有价值;所以(摆脱编译器的恼人警告)我只是使用:

   public override int GetHashCode()
   {
      return base.GetHashCode();
   }

(Of course I could use a #pragma to turn off the warning as well but I prefer this way.)

(当然我也可以使用#pragma来关闭警告,但我更喜欢这种方式。)

When you are in the position that you do need the performance than all of the issues mentioned by others here apply, of course. Most important - otherwise you will get wrong results when retrieving items from a hash set or dictionary: the hash code must not vary with the life time of an object (more accurately, during the time whenever the hash code is needed, such as while being a key in a dictionary): for example, the following is wrong as Value is public and so can be changed externally to the class during the life time of the instance, so you must not use it as the basis for the hash code:

当你处于这样的位置时,你确实需要表现,而不是其他人提到的所有问题。最重要的是 - 否则在从哈希集或字典中检索项时会得到错误的结果:哈希代码不得随对象的生命周期而变化(更准确地说,在需要哈希代码的时间内,例如在字典中的一个键):例如,以下是错误的,因为Value是公共的,因此可以在实例的生命周期内从外部更改为类,因此您不能将其用作哈希代码的基础:


   class A
   {
      public int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //WRONG! Value is not constant during the instance's life time
      }
   }    

On the other hand, if Value can't be changed it's ok to use:

另一方面,如果Value无法更改,则可以使用:


   class A
   {
      public readonly int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //OK  Value is read-only and can't be changed during the instance's life time
      }
   }

#11


0  

It's my understanding that the original GetHashCode() returns the memory address of the object, so it's essential to override it if you wish to compare two different objects.

我的理解是原始的GetHashCode()返回对象的内存地址,因此如果你想比较两个不同的对象,必须覆盖它。

EDITED: That was incorrect, the original GetHashCode() method cannot assure the equality of 2 values. Though objects that are equal return the same hash code.

编辑:这是不正确的,原始的GetHashCode()方法不能保证2个值的相等。虽然相等的对象返回相同的哈希码。

#12


-5  

Below using reflection seems to me a better option considering public properties as with this you don't have have to worry about addition / removal of properties (although not so common scenario). This I found to be performing better also.(Compared time using Diagonistics stop watch).

以下使用反射在我看来是一个更好的选择考虑公共属性,因为你不必担心添加/删除属性(虽然不常见的情况)。我发现这也表现得更好。(使用Diagonistics秒表比较时间)。

    public int getHashCode()
    {
        PropertyInfo[] theProperties = this.GetType().GetProperties();
        int hash = 31;
        foreach (PropertyInfo info in theProperties)
        {
            if (info != null)
            {
                var value = info.GetValue(this,null);
                if(value != null)
                unchecked
                {
                    hash = 29 * hash ^ value.GetHashCode();
                }
            }
        }
        return hash;  
    }

#1


1157  

Yes, it is important if your item will be used as a key in a dictionary, or HashSet<T>, etc - since this is used (in the absence of a custom IEqualityComparer<T>) to group items into buckets. If the hash-code for two items does not match, they may never be considered equal (Equals will simply never be called).

是的,重要的是如果您的项目将用作字典中的键或HashSet 等 - 因为这是使用(在没有自定义IEqualityComparer 的情况下)将项目分组到存储桶中。如果两个项的哈希码不匹配,它们可能永远不会被认为是相等的(Equals将永远不会被调用)。

The GetHashCode() method should reflect the Equals logic; the rules are:

GetHashCode()方法应该反映Equals逻辑;规则是:

  • if two things are equal (Equals(...) == true) then they must return the same value for GetHashCode()
  • 如果两个东西相等(Equals(...)== true)那么它们必须为GetHashCode()返回相同的值

  • if the GetHashCode() is equal, it is not necessary for them to be the same; this is a collision, and Equals will be called to see if it is a real equality or not.
  • 如果GetHashCode()相等,则它们不必相同;这是一个碰撞,并且将调用Equals以查看它是否是真正的平等。

In this case, it looks like "return FooId;" is a suitable GetHashCode() implementation. If you are testing multiple properties, it is common to combine them using code like below, to reduce diagonal collisions (i.e. so that new Foo(3,5) has a different hash-code to new Foo(5,3)):

在这种情况下,它看起来像“返回FooId;”是一个合适的GetHashCode()实现。如果您正在测试多个属性,通常使用如下代码组合它们,以减少对角线冲突(即,使新Foo(3,5)具有与新Foo(5,3)不同的哈希码):

int hash = 13;
hash = (hash * 7) + field1.GetHashCode();
hash = (hash * 7) + field2.GetHashCode();
...
return hash;

Oh - for convenience, you might also consider providing == and != operators when overriding Equals and GetHashCode.

哦 - 为方便起见,在覆盖Equals和GetHashCode时,您可能还会考虑提供==和!=运算符。


A demonstration of what happens when you get this wrong is here.

当你弄错了会发生什么事的证明就在这里。

#2


125  

It's actually very hard to implement GetHashCode() correctly because, in addition to the rules Marc already mentioned, the hash code should not change during the lifetime of an object. Therefore the fields which are used to calculate the hash code must be immutable.

实际上很难正确实现GetHashCode(),因为除了Marc已经提到的规则之外,哈希代码在对象的生命周期内不应该改变。因此,用于计算哈希码的字段必须是不可变的。

I finally found a solution to this problem when I was working with NHibernate. My approach is to calculate the hash code from the ID of the object. The ID can only be set though the constructor so if you want to change the ID, which is very unlikely, you have to create a new object which has a new ID and therefore a new hash code. This approach works best with GUIDs because you can provide a parameterless constructor which randomly generates an ID.

当我使用NHibernate时,我终于找到了解决这个问题的方法。我的方法是根据对象的ID计算哈希码。只能通过构造函数设置ID,因此如果要更改ID,这是非常不可能的,您必须创建一个具有新ID的新对象,因此需要新的哈希代码。这种方法最适用于GUID,因为您可以提供随机生成ID的无参数构造函数。

#3


46  

By overriding Equals you're basically stating that you are the one who knows better how to compare two instances of a given type, so you're likely to be the best candidate to provide the best hash code.

通过重写Equals,您基本上声明自己是更了解如何比较给定类型的两个实例的人,因此您可能是提供最佳哈希码的最佳候选者。

This is an example of how ReSharper writes a GetHashCode() function for you:

这是ReSharper如何为您编写GetHashCode()函数的示例:

public override int GetHashCode()
{
    unchecked
    {
        var result = 0;
        result = (result * 397) ^ m_someVar1;
        result = (result * 397) ^ m_someVar2;
        result = (result * 397) ^ m_someVar3;
        result = (result * 397) ^ m_someVar4;
        return result;
    }
}

As you can see it just tries to guess a good hash code based on all the fields in the class, but since you know your object's domain or value ranges you could still provide a better one.

正如您所看到的,它只是尝试根据类中的所有字段来猜测一个好的哈希代码,但由于您知道对象的域或值范围,因此您仍然可以提供更好的哈希代码。

#4


34  

Please don´t forget to check the obj parameter against null when overriding Equals(). And also compare the type.

在重写Equals()时,请不要忘记检查obj参数是否为null。并且还比较类型。

public override bool Equals(object obj)
{
    if (obj == null || GetType() != obj.GetType())
        return false;

    Foo fooItem = obj as Foo;

    return fooItem.FooId == this.FooId;
}

The reason for this is: Equals must return false on comparison to null. See also http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

原因是:与null相比,Equals必须返回false。另请参见http://msdn.microsoft.com/en-us/library/bsc2ak47.aspx

#5


26  

How about:

public override int GetHashCode()
{
    return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}

Assuming performance is not an issue :)

假设性能不是问题:)

#6


9  

It is because the framework requires that two objects that are the same must have the same hashcode. If you override the equals method to do a special comparison of two objects and the two objects are considered the same by the method, then the hash code of the two objects must also be the same. (Dictionaries and Hashtables rely on this principle).

这是因为框架要求两个相同的对象必须具有相同的哈希码。如果重写equals方法以对两个对象进行特殊比较,并且方法认为两个对象相同,则两个对象的哈希码也必须相同。 (字典和Hashtables依赖于这个原则)。

#7


9  

Just to add on above answers:

只是添加以上答案:

If you don't override Equals then the default behavior is that references of the objects are compared. The same applies to hashcode - the default implmentation is typically based on a memory address of the reference. Because you did override Equals it means the correct behavior is to compare whatever you implemented on Equals and not the references, so you should do the same for the hashcode.

如果不重写等于,则默认行为是比较对象的引用。这同样适用于hashcode - 默认的implmentation通常基于引用的内存地址。因为你确实覆盖了Equals,所以它意味着正确的行为是比较你在Equals而不是引用上实现的任何东西,所以你应该对hashcode做同样的事情。

Clients of your class will expect the hashcode to have similar logic to the equals method, for example linq methods which use a IEqualityComparer first compare the hashcodes and only if they're equal they'll compare the Equals() method which might be more expensive to run, if we didn't implement hashcode, equal object will probably have different hashcodes (because they have different memory address) and will be determined wrongly as not equal (Equals() won't even hit).

您的类的客户端将期望哈希码具有与equals方法类似的逻辑,例如使用IEqualityComparer的linq方法首先比较哈希码,并且只有当它们相等时它们才会比较可能更昂贵的Equals()方法如果我们没有实现hashcode,那么equ对象可能会有不同的hashcode(因为它们有不同的内存地址),并且会被错误地判断为不相等(Equals()甚至不会命中)。

In addition, except the problem that you might not be able to find your object if you used it in a dictionary (because it was inserted by one hashcode and when you look for it the default hashcode will probably be different and again the Equals() won't even be called, like Marc Gravell explains in his answer, you also introduce a violation of the dictionary or hashset concept which should not allow identical keys - you already declared that those objects are essentially the same when you overrode Equals so you don't want both of them as different keys on a data structure which suppose to have a unique key. But because they have a different hashcode the "same" key will be inserted as different one.

此外,除了您在字典中使用它时可能无法找到对象的问题(因为它是由一个哈希码插入的,当您查找它时,默认哈希码可能会有所不同,而且Equals()甚至不会被调用,就像Marc Gravell在他的回答中解释的那样,你也引入了违反字典或hashset概念的行为,它不应该允许相同的键 - 你已经声明当你覆盖Equals时这些对象基本相同所以你不要不希望它们都是数据结构上的不同键,它们假设有一个唯一键。但是因为它们有不同的哈希码,所以“相同”键将作为不同的键插入。

#8


8  

We have two problems to cope with.

我们有两个问题需要解决。

  1. You cannot provide a sensible GetHashCode() if any field in the object can be changed. Also often a object will NEVER be used in a collection that depends on GetHashCode(). So the cost of implementing GetHashCode() is often not worth it, or it is not possible.

    如果可以更改对象中的任何字段,则无法提供合理的GetHashCode()。通常,对象永远不会在依赖于GetHashCode()的集合中使用。因此,实现GetHashCode()的成本通常是不值得的,或者是不可能的。

  2. If someone puts your object in a collection that calls GetHashCode() and you have overrided Equals() without also making GetHashCode() behave in a correct way, that person may spend days tracking down the problem.

    如果有人将您的对象放入一个调用GetHashCode()的集合中并且您已经覆盖了Equals()而没有使GetHashCode()以正确的方式运行,那么该人可能需要花费数天时间来追踪问题。

Therefore by default I do.

因此默认情况下我这样做。

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }

    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;

        return fooItem.FooId == this.FooId;
    }

    public override int GetHashCode()
    {
        // Some comment to explain if there is a real problem with providing GetHashCode() 
        // or if I just don't see a need for it for the given class
        throw new Exception("Sorry I don't know what GetHashCode should do for this class");
    }
}

#9


5  

Hash code is used for hash-based collections like Dictionary, Hashtable, HashSet etc. The purpose of this code is to very quickly pre-sort specific object by putting it into specific group (bucket). This pre-sorting helps tremendously in finding this object when you need to retrieve it back from hash-collection because code has to search for your object in just one bucket instead of in all objects it contains. The better distribution of hash codes (better uniqueness) the faster retrieval. In ideal situation where each object has a unique hash code, finding it is an O(1) operation. In most cases it approaches O(1).

散列代码用于基于散列的集合,如Dictionary,Hashtable,HashSet等。此代码的目的是通过将特定对象放入特定组(存储桶)来非常快速地对其进行预排序。当您需要从哈希集合中检索此对象时,这种预排序有助于查找此对象,因为代码必须仅在一个存储桶中搜索您的对象,而不是在其包含的所有对象中搜索对象。哈希码的更好分布(更好的唯一性)更快的检索。在每个对象具有唯一哈希码的理想情况下,找到它是O(1)操作。在大多数情况下,它接近O(1)。

#10


4  

It's not necessarily important; it depends on the size of your collections and your performance requirements and whether your class will be used in a library where you may not know the performance requirements. I frequently know my collection sizes are not very large and my time is more valuable than a few microseconds of performance gained by creating a perfect hash code; so (to get rid of the annoying warning by the compiler) I simply use:

它不一定重要;这取决于您的集合的大小和您的性能要求,以及您的类是否将用于您可能不知道性能要求的库中。我经常知道我的集合大小不是很大,而且我的时间比通过创建完美的哈希码获得的几微秒的性能更有价值;所以(摆脱编译器的恼人警告)我只是使用:

   public override int GetHashCode()
   {
      return base.GetHashCode();
   }

(Of course I could use a #pragma to turn off the warning as well but I prefer this way.)

(当然我也可以使用#pragma来关闭警告,但我更喜欢这种方式。)

When you are in the position that you do need the performance than all of the issues mentioned by others here apply, of course. Most important - otherwise you will get wrong results when retrieving items from a hash set or dictionary: the hash code must not vary with the life time of an object (more accurately, during the time whenever the hash code is needed, such as while being a key in a dictionary): for example, the following is wrong as Value is public and so can be changed externally to the class during the life time of the instance, so you must not use it as the basis for the hash code:

当你处于这样的位置时,你确实需要表现,而不是其他人提到的所有问题。最重要的是 - 否则在从哈希集或字典中检索项时会得到错误的结果:哈希代码不得随对象的生命周期而变化(更准确地说,在需要哈希代码的时间内,例如在字典中的一个键):例如,以下是错误的,因为Value是公共的,因此可以在实例的生命周期内从外部更改为类,因此您不能将其用作哈希代码的基础:


   class A
   {
      public int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //WRONG! Value is not constant during the instance's life time
      }
   }    

On the other hand, if Value can't be changed it's ok to use:

另一方面,如果Value无法更改,则可以使用:


   class A
   {
      public readonly int Value;

      public override int GetHashCode()
      {
         return Value.GetHashCode(); //OK  Value is read-only and can't be changed during the instance's life time
      }
   }

#11


0  

It's my understanding that the original GetHashCode() returns the memory address of the object, so it's essential to override it if you wish to compare two different objects.

我的理解是原始的GetHashCode()返回对象的内存地址,因此如果你想比较两个不同的对象,必须覆盖它。

EDITED: That was incorrect, the original GetHashCode() method cannot assure the equality of 2 values. Though objects that are equal return the same hash code.

编辑:这是不正确的,原始的GetHashCode()方法不能保证2个值的相等。虽然相等的对象返回相同的哈希码。

#12


-5  

Below using reflection seems to me a better option considering public properties as with this you don't have have to worry about addition / removal of properties (although not so common scenario). This I found to be performing better also.(Compared time using Diagonistics stop watch).

以下使用反射在我看来是一个更好的选择考虑公共属性,因为你不必担心添加/删除属性(虽然不常见的情况)。我发现这也表现得更好。(使用Diagonistics秒表比较时间)。

    public int getHashCode()
    {
        PropertyInfo[] theProperties = this.GetType().GetProperties();
        int hash = 31;
        foreach (PropertyInfo info in theProperties)
        {
            if (info != null)
            {
                var value = info.GetValue(this,null);
                if(value != null)
                unchecked
                {
                    hash = 29 * hash ^ value.GetHashCode();
                }
            }
        }
        return hash;  
    }