给定以下类别

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表示Foos表的一行。哪个是重写GetHashCode的首选方法?

为什么重写GetHashCode很重要?


当前回答

通过重写Equals,您基本上表明您更了解如何比较给定类型的两个实例。

下面可以看到ReSharper如何为您编写GetHashCode()函数的示例。请注意,这段代码是由程序员调整的:

public override int GetHashCode()
{
    unchecked
    {
        var result = 0;
        result = (result * 397) ^ m_someVar1;
        result = (result * 397) ^ m_someVar2;
        result = (result * 397) ^ m_someVar3;
        result = (result * 397) ^ m_someVar4;
        return result;
    }
}

正如您所看到的,它只是试图根据类中的所有字段猜测一个好的哈希代码,但如果您知道对象的域或值范围,您仍然可以提供一个更好的哈希代码。

其他回答

从C#9(.net5或.netcore3.1)开始,您可能希望使用记录,因为默认情况下它使用基于值的相等。

怎么样:

public override int GetHashCode()
{
    return string.Format("{0}_{1}_{2}", prop1, prop2, prop3).GetHashCode();
}

假设性能不是问题:)

我的理解是,原始的GetHashCode()返回对象的内存地址,因此如果您希望比较两个不同的对象,则必须重写它。

编辑:这是错误的,原始的GetHashCode()方法无法确保2个值相等。虽然相等的对象返回相同的哈希代码。

在我看来,考虑到公共财产,下面使用反射似乎是一个更好的选择,因为在此情况下,您不必担心财产的添加/删除(尽管不太常见)。我发现这也表现得更好。(使用诊断学秒表比较时间)。

    public int getHashCode()
    {
        PropertyInfo[] theProperties = this.GetType().GetProperties();
        int hash = 31;
        foreach (PropertyInfo info in theProperties)
        {
            if (info != null)
            {
                var value = info.GetValue(this,null);
                if(value != null)
                unchecked
                {
                    hash = 29 * hash ^ value.GetHashCode();
                }
            }
        }
        return hash;  
    }

从.NET 4.7开始,重写GetHashCode()的首选方法如下所示。如果目标是较旧的.NET版本,请包含System.ValueTuple nuget包。

// C# 7.0+
public override int GetHashCode() => (FooId, FooName).GetHashCode();

在性能方面,该方法将优于大多数复合哈希代码实现。ValueTuple是一个结构,因此不会有任何垃圾,而底层算法的速度也很快。