获取int和Nullable <int>对的哈希码</int>

时间:2010-08-31 10:25:05

标签: c# dictionary hash

目前,我正在使用以下类作为我的关键字,用于对象的词典集合,这些对象由ColumnID和可空的SubGroupID独有:

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位整数相结合,但我不确定如何处理null SubGroupIDs。这是我得到的,但它无效,因为SubGroupID可以为零:

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

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

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

如果您可以安全地将任意一个整数的值范围限制为仅31位,那么您就可以按原样大致打包它们。但是,你不会以这种方式获得任何优势 - 你也可以直接像这样计算哈希码(感谢Resharper的样板代码生成):

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

答案 1 :(得分:2)

您似乎将GetHashCode视为唯一键。事实并非如此。 HashCodes是32位整数,并不是唯一的,只能在32位空间内良好分布,以最大限度地减少冲突的可能性。试试这个ColumnDataKey的GetHashCode方法:

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

这里的幻数是397,一个素数,由于巫毒魔法的原因是一个很好的数字乘以混合你的位(并且是ReSharper团队选择的数字),和-11111111,一个子组ID我认为这在实践中不太可能出现。