C# 不可变类型的哈希代码

C# 不可变类型的哈希代码,c#,.net,immutability,C#,.net,Immutability,关于散列码,不可变类型有什么考虑吗 我应该在构造函数中生成一次吗 您如何明确散列码是固定的?我应该吗?如果是这样,使用名为HashCode的属性而不是GetHashCode方法是否更好?这有什么缺点吗?(考虑到这两种方法都可以,但建议使用属性)。我会在第一次调用getHashCode时生成一次哈希代码,然后缓存它以备以后调用。这样可以避免在可能不需要它时在构造函数中调用它 如果您不希望为每个值对象多次调用getHashCode,那么可能根本不需要缓存该值。为什么需要确保hashcode是固定的?

关于散列码,不可变类型有什么考虑吗

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


您如何明确散列码是固定的?我应该吗?如果是这样,使用名为HashCode的属性而不是GetHashCode方法是否更好?这有什么缺点吗?(考虑到这两种方法都可以,但建议使用属性)。

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


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

为什么需要确保hashcode是固定的?哈希代码的语义是,对于对象的任何给定状态,它始终是相同的值。因为对象是不可变的,所以这是一个给定的值。如何选择实现GetHashCode取决于您


让它成为一个返回的私有字段是一种选择——它小、简单、快速。

我通常不会在构造函数中生成它,但在决定是否缓存它之前,我还想知道更多关于预期用途的信息

您是否希望得到少量实例,这些实例会被大量散列,并且需要很长时间来计算散列?如果是这样,缓存可能是合适的。如果您希望有大量可能“扔掉”的实例,我就不必费心缓存了

有趣的是,.NET和Java在这方面对字符串做了不同的选择-Java缓存哈希,.NET没有。考虑到许多字符串实例从不进行散列,而那些被散列的实例通常只进行一次散列(例如,在插入到散列表中时),我认为我支持.NET的决定

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


你当然不需要单独的财产。除非有人更改对象的状态,否则哈希代码应该始终保持不变——如果您的类型是不可变的,那么您已经禁止了该操作,因此用户不应该期望任何更改。只需重写GetHashCode()

好吧,您必须有一个GetHashCode()重写方法,因为这就是消费者检索您的hashcode的方式。大多数哈希代码都是相当简单的算术运算,执行速度很快。您是否有理由相信缓存结果(需要占用内存)会显著提高性能

开始简单-动态生成哈希代码。如果您认为可以看到缓存它的性能改进,请先测试

法规要求我在这里引用“过早优化是万恶之源”这句话

关于散列码,不可变类型有什么考虑吗

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

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

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

您如何明确散列码是固定的

我不明白这个问题。更改哈希代码是例外,而不是规则。散列码总是被认为是不变的。如果对象的哈希代码发生更改,那么该对象可能会在哈希表中“丢失”,因此每个人都应该假设哈希代码保持稳定

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

对象的哪个使用者会说“好吧,我可以调用GetHashCode(),一个保证对所有对象都有效的方法,但是我要调用这个HashCode getter,它做的事情完全相同”?你心目中有这样的消费者吗


如果您没有任何功能消费者,那么就不要提供该功能。

一般来说,计算哈希代码应该很快。因此,缓存不应该是一个很大的优化,也不值得这么麻烦

如果评测确实显示GethashCode需要花费大量时间,那么您可能应该将其缓存,作为一种修复


但是我不认为这是正常做法的一部分。 根据我个人的经验,我知道开发人员非常擅长错误判断性能问题


因此,建议在GetHashCode()中动态计算哈希代码时,尽量简化所有操作。

谢谢Jon。我的案例中有大量的这种类型,比如数百万。所以每次调用GetHashCode时我都应该计算hash代码,对吗?System.String hashcode实现很糟糕,很好.NET没有缓存它。是的,听起来像是在运行时计算hash代码是一种方法。当您有很多实例时,每个实例可以装载四个字节(假设它是一个相当小的类型,并且hashcode不需要很长时间就可以实现),是的,基本的