在不可变类型的构造函数中生成HashCode

时间:2009-05-26 11:10:51

标签: c# .net constructor

我对不可变类型的HashCode有一些疑问。

  • 我可以“预先”在构造函数中生成不可变类型的HashCode,还是有任何理由不这样做?
  • 当调用方法GetHashCode()时,我是否应该再次生成Hashcode?

这是一个示例类:

    public class Id  {

        private readonly object _value;

        private readonly int _hash = -1;


        public Id( object value ) {
          _value = value;
          _hash = ( int ) ( 7 * value.GetType().GetHashCode() + 7 + 7 * _value.GetHashCode() );
        }

        public object Value {
          get {
            return _value;
          }
        }

        public override int GetHashCode() {
          return _hash;
        }

        public override bool Equals( object obj ) {
          Id other = obj as Id;

          if ( other == null ) {
            return false;
          }

          return this.GetHashCode() == other.GetHashCode();
        }
        }

3 个答案:

答案 0 :(得分:8)

您可以预生成哈希码,但为什么?只需在需要时生成它(在GetHashCode中),然后可以存储它 - 大多数对象永远不需要有一个哈希,所以它只会减慢程序。

  

当调用方法GetHashCode()时,我是否应该再次生成Hashcode?

不可变对象的哈希码应始终相同,因此无论是再次生成还是存储它都不会产生任何影响,除非存储会提高性能。

注意:您不能通过比较HashCodes来定义Equals - 两个不同的对象可能具有相等的HashCodes(hash collsion)。

答案 1 :(得分:3)

这实际上取决于用例。

你经常使用哈希吗?然后预生成它,因为对象是不可变的,每次计算它都是不必要的,因为结果总是相同的。

是不是哈希使用了很多?然后不要预生成它,因为它会不必要地减慢程序,计算可能不会使用的哈希。

第三个(也是最好的,在我看来)选项是计算GetHashCode中的散列并缓存结果,仅计算一次散列并在此后每次返回此缓存散列。这样,在从未使用过时,没有时间计算哈希值,也不会在每次调用GetHashCode时不必要地计算哈希值。虽然这确实意味着内存用于在对象中存储哈希。

答案 2 :(得分:1)

不要预生成的原因:它减慢了对象的创建速度。

始终重新生成的原因:您保存了保留哈希码所需的存储空间。

为了记录,我可能会预先计算哈希码并将其存储为不可变对象,除非分析显示它很昂贵并且我不经常访问该值。