不可变类型的哈希码

Joa*_*nge 5 .net c# immutability

有关哈希码的不可变类型是否有任何考虑因素?

我应该在构造函数中生成一次吗?

您如何明确哈希码是否已修复?我是不是该?如果是这样,使用名为HashCode的属性而不是GetHashCode方法更好吗?会有任何缺点吗?(考虑两者都可行,但建议财产).

Eri*_*ert 18

有关哈希码的不可变类型是否有任何考虑因素?

不可变类型是正确散列的最简单类型; 散列可变数据时会发生大多数哈希码错误.最重要的是哈希和平等一致; 如果两个实例比较相等,则它们应具有相同的哈希码.(反过来不一定正确;具有相同散列的两个实例不必相等.)

我应该在构造函数中生成一次吗?

这是一种性能优化技术; 通过这样做,您可以交换增加的空间消耗(用于存储计算值)以减少可能的时间.我从不进行性能优化,除非它们是由现实的,以客户为中心的性能测试驱动的,这些性能测试仔细测量两个选项的性能与文档目标.如果您精心设计的实验表明(1)未能这样做会导致您错过目标,并且(2)这样做会导致您达到目标,那么您应该这样做.

您如何明确哈希码是否已修复?

我不明白这个问题.更改哈希码是例外,而不是规则.哈希码始终应该是不变的.如果对象的哈希码发生变化,那么对象可能会在哈希表中"丢失",因此每个人都应该假设哈希码保持稳定.

使用名为HashCode的属性而不是GetHashCode方法更好吗?

您的对象的消费者会说"好吧,我可以调用GetHashCode(),这是一种保证在所有对象上的方法,但我会调用这个完全相同的HashCode getter"?你有这样的消费者吗?

如果您没有任何功能消费者,请不要提供该功能.


Jon*_*eet 9

我通常不会在构造函数中生成它,但我还想在决定是否缓存之前了解有关预期用法的更多信息.

您是否期望少量实例,这些实例会被大量扫描并且需要很长时间来计算哈希值?如果是这样,缓存可能是适当的.如果您期待大量潜在的"丢失"实例,我不会打扰缓存.

有趣的是,.NET和Java在这方面为String做出了不同的选择 - Java缓存哈希,而.NET则不然.鉴于许多字符串实例从未散列,和那些散列往往只散列一次(例如,在插入哈希表),我想我在这里赞成.NET的决定.

基本上你是在与速度交易记忆+复杂性.正如Michael所说,在使代码更复杂之前进行测试.当然在某些情况下(例如对于类库),您无法准确预测实际使用情况,但在许多情况下,您会有一个非常好的主意.

你当然不需要一个单独的财产.除非有人更改对象的状态,否则哈希代码应始终保持不变 - 如果您的类型是不可变的,那么您已经禁止这样做,因此用户不应期待任何更改.只是覆盖GetHashCode().


Bil*_*ard 4

我会在第一次调用时生成一次哈希码getHashCode,然后将其缓存以供以后调用。这可以避免在不需要时在构造函数中调用它。

如果您不希望getHashCode对每个值对象调用很多次,则可能根本不需要缓存该值。