2010-08-31 40 views
0

目前我使用下面的类作为我对通过ColumnID是唯一对象的词典收集和键可为空SubGroupID获取哈希码的int和可空<int>对

public class ColumnDataKey 
{ 
    public int ColumnID { get; private set; } 
    public int? SubGroupID { get; private set; } 

    // ... 

    public override int GetHashCode() 
    { 
     var hashKey = this.ColumnID + "_" + 
      (this.SubGroupID.HasValue ? this.SubGroupID.Value.ToString() : "NULL"); 
     return hashKey.GetHashCode(); 
    } 
} 

我想不知怎么把这个结合到一个64位整数,但我不知道如何处理空SubGroupIDs。这是据我得到的,但它也不是一个有效SubGroupID可以为零:

var hashKey = (long)this.ColumnID << 32 + 
    (this.SubGroupID.HasValue ? this.SubGroupID.Value : 0); 
return hashKey.GetHashCode(); 

任何想法?

+0

@downvoter - 为什么? – Codesleuth 2013-06-11 22:24:46

回答

3

严格地说,你将无法将这些完美地结合起来,因为逻辑上int?有33位信息(32位表示整数,另一位表示值是否存在)。您的不可为空int具有信息总共制造65位的进一步的32位,但一个long只有64位。

如果你可以安全地限制任一整数的只有31位的数值范围内,那么你可以粗略地收拾他们为你已经做。但是,你不会得到任何优势做这样 - 你可能也只是计算散列码直接像这样(感谢ReSharper的样板代码生成):

public override int GetHashCode() 
{ 
    unchecked 
    { 
     return (ColumnID*397)^(SubGroupID.HasValue ? SubGroupID.Value : 0); 
    } 
} 
+0

我明白了,很好的回答!我正在研究'SubGroupID'的范围 - 它看起来像它永远不会低于零,所以我希望这意味着我可以剥下它一点,并使用最后一位意味着'空'? – Codesleuth 2010-08-31 10:35:43

+0

这就像一个魅力!按照Matt的建议,我将零更改为-11,111,111,但基本上我已经使用了您的答案。谢谢! – Codesleuth 2010-08-31 10:52:55

2

你似乎在思考的GetHashCode作为唯一键。事实并非如此。 HashCodes是32位整数,并不意味着是唯一的,只有在32位空间中分布良好才能将冲突概率降至最低。尝试此ColumnDataKey你的GetHashCode方法:这里

ColumnID * 397^(SubGroupID.HasValue ?? SubGroupID.Value : -11111111) 

神奇的数字是397,一个素数,这对于巫术的原因是一个很好的数目乘以混淆了你的比特(并且是多少ReSharper团队选择)和-11111111,我认为这是我认为在实践中不太可能出现的子集团ID。

+0

这似乎甚至不会在实践中出现-1。我会尽量把你的答案和丹尼尔的结合起来。 – Codesleuth 2010-08-31 10:45:55