重写 GetHashCode() 方法

13 浏览
0 Comments

重写 GetHashCode() 方法

这篇文章中,Jon Skeet提到他通常使用这种算法来重写GetHashCode()方法。\n

public override int GetHashCode()
{
  unchecked //溢出是可以的,只需包装
  {
    int hash = 17;
    //当然要进行适当的空检查等操作 :)
    hash = hash * 23 + Id.GetHashCode();
    return hash;
  }
}

\n现在,我尝试使用这种方法,但Resharper告诉我GetHashCode()方法应该只使用只读字段进行哈希(尽管它可以编译通过)。那么现在有什么好的做法呢?因为我现在无法将我的字段设置为只读。\n我尝试使用Resharper生成这个方法,以下是结果。\n

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

\n这实际上没有什么贡献...

0
0 Comments

Overriding GetHashCode() is an important aspect of implementing custom equality in C#. It is used to generate a unique numeric value for an object, which is then used to determine the bucket in which the object will be stored in a dictionary or hashset. However, there is a potential issue when multiple types with different GetHashCode() implementations are stored in the same collection.

The problem arises when the GetHashCode() method returns the same numeric value for different types. This can lead to poor performance when performing lookups in the collection, as objects of different types will be put in different buckets. To address this issue, it is recommended to return a different numeric value for each implementation of GetHashCode() in a class that has no immutable fields.

One approach to achieve this is to use prime numbers to generate the numeric values. By using prime numbers, a better distribution of objects across the buckets can be achieved, resulting in better performance during lookups. The use of prime numbers in hash functions is a widely accepted practice in computer science.

It should be noted that using prime numbers in GetHashCode() is particularly useful when dealing with classes that have readonly fields. In such cases, the use of prime numbers can help achieve better distribution over the buckets of a dictionary or hashset.

In conclusion, the overriding GetHashCode() method is crucial for implementing custom equality in C#. By returning different numeric values for each implementation, and using prime numbers to achieve better distribution, the performance of lookups in dictionaries and hashsets can be significantly improved.

0
0 Comments

在使用 GetHashCode() 方法时,需要注意它必须与 Equals 方法相辅相成。如果可以使用引用相等性(当您从不会有两个不同的实例可以相等时),那么可以安全地使用从 Object 继承的 Equals 和 GetHashCode 方法。这比仅仅从 GetHashCode 返回 1 的方法要好得多。

然而,有时候我们需要自定义 Equals 和 GetHashCode 方法,以便在比较对象时能够正确地判断它们是否相等。这是由于默认的 Equals 和 GetHashCode 方法是基于引用相等性的,而对于自定义的类,我们往往需要根据对象的属性来判断它们是否相等。

但是,仅仅自定义 Equals 方法可能还不够,因为在使用哈希表等数据结构时,我们通常会使用 GetHashCode 方法来快速定位对象。如果 GetHashCode 方法没有正确地实现,可能会导致相等的对象在哈希表中无法被正确找到。

因此,我们需要重写 GetHashCode 方法,以确保相等的对象具有相同的哈希码。这样,在哈希表中查找对象时,可以使用对象的哈希码进行快速定位,提高性能。

解决方法是根据对象的属性计算出一个哈希码,并返回该哈希码。通常,我们可以使用一种算法,如乘法哈希、位运算等来计算哈希码。这样,相等的对象将具有相同的哈希码,从而在哈希表中能够正确找到它们。

总结起来,当我们需要自定义 Equals 方法时,通常也需要重写 GetHashCode 方法。通过正确实现 GetHashCode 方法,可以保证相等的对象具有相同的哈希码,从而在哈希表等数据结构中能够正确找到它们。这样可以提高程序的性能和效率。

0
0 Comments

问题出现的原因是,如果在可变字段上实现了GetHashCode方法,那么返回的哈希码将始终相同,这会导致所有对象都被放入散列集合的同一个桶中。这样一来,在查找对象时,必须对桶中的每个对象进行相等性检查,就像在链表中进行搜索一样。这种实现方式是低效且容易出错的。

解决方法是,在实现GetHashCode方法时,应该基于不可变字段来计算哈希码。如果对象的字段是可变的,那么在将对象添加到散列集合之后,不应该再更改这些字段。这样可以保证哈希码的一致性,并且能够正确地在散列集合中查找对象。

对于结构体来说,字段也应该是不可变的。大多数人都认同结构体应该是不可变的,因此所有字段都应该是只读的(或至少是私有的,并且在结构体创建后不会被更改),并且哈希算法应该使用所有字段(与Equals相关)来计算哈希码。

虽然在C#中无法强制实施不可变性,但这并不意味着我们应该放弃对可变对象的更改。在编写C#应用程序时,有许多无法证明的代码约束条件必须满足,而“在构造之后不再更改”的合约并不是不合理的。人们在完全动态的语言中构建了大型应用程序,缺乏静态验证是有问题的,但并非致命的。因此,解决方案是接受在C#中无法实际实施不可变性,并继续前进。

0