C# 哈希函数用于字典查找

19 浏览
0 Comments

C# 哈希函数用于字典查找

给出以下类

public class Foo
{
    public int FooId { get; set; }
    public string FooName { get; set; }
    public override bool Equals(object obj)
    {
        Foo fooItem = obj as Foo;
        if (fooItem == null) 
        {
           return false;
        }
        return fooItem.FooId == this.FooId;
    }
    public override int GetHashCode()
    {
        // Which is preferred?
        return base.GetHashCode();
        //return this.FooId.GetHashCode();
    }
}

我重写了Equals方法,因为Foo代表Foo表的一行。哪种方法是重写GetHashCode的首选方法?

重写GetHashCode为什么很重要?

admin 更改状态以发布 2023年5月22日
0
0 Comments

实现GetHashCode()是非常困难的,因为除了Marc已经提到的规则之外,哈希码在对象的生命周期中不应更改。因此,用于计算哈希码的字段必须是不可变的。

当我正在使用NHibernate时,我最终找到了解决此问题的方法。
我的方法是根据对象的ID计算哈希码。ID只能通过构造函数设置,因此如果您想更改ID(这是非常不可能的),您必须创建一个新对象,该对象具有新的ID和因此是新的哈希码。这种方法最适合GUID,因为您可以提供一个无参数的构造函数,该函数会随机生成ID。

0
0 Comments

如果您的项将用作字典或HashSet等中的键,则很重要,因为在没有自定义IEqualityComparer的情况下,这将用于将项分组成桶。如果两个项的哈希代码不匹配,则它们可能永远不会被视为相等(Equals将根本不会被调用)。

GetHashCode()方法应反映Equals逻辑;规则如下:

  • 如果两个事物相等(Equals(...) == true),则它们必须返回GetHashCode()的相同值
  • 如果GetHashCode()相等,则它们不一定相同;这是一种碰撞,Equals将被调用以查看它是否是真正的相等性。

在这种情况下,像"return FooId;"这样的GetHashCode()实现是合适的。如果您正在测试多个属性,通常使用以下代码将它们组合在一起,以减少对角线碰撞(即使new Foo(3,5)具有与new Foo(5,3)不同的哈希代码):

在现代框架中,HashCode类型具有帮助您从多个值创建哈希码的方法;在旧框架中,您需要在没有的情况下进行操作,因此类似于以下内容的代码:

unchecked // only needed if you're compiling with arithmetic checks enabled
{ // (the default compiler behaviour is *disabled*, so most folks won't need this)
    int hash = 13;
    hash = (hash * 7) + field1.GetHashCode();
    hash = (hash * 7) + field2.GetHashCode();
    ...
    return hash;
}

哦 - 为了方便起见,当覆盖EqualsGetHashCode时,您还可以考虑提供==!=运算符。


示例和讨论链接看这里

0