25

RuntimeHelpers.GetHashCode(object)方法允许基于对象的身份生成哈希码。MSDN状态

RuntimeHelpers.GetHashCode 方法始终以非虚拟方式调用 Object.GetHashCode 方法,即使对象的类型已覆盖 Object.GetHashCode 方法。

[MethodImpl(MethodImplOptions.InternalCall)]
[SecuritySafeCritical]
public static extern int GetHashCode(object o);

但是,当Object.GetHashCode()使用 Reflector (.NET 4.0) 检查方法时,我们将看到以下代码:

public virtual int GetHashCode()
{
    return RuntimeHelpers.GetHashCode(this);
}

这让我相信 MSDN 文档是错误的,因为Object.GetHashCode从内部调用RuntimeHelpers.GetHashCode(object)会导致堆栈溢出。

那么它的实际行为是什么RuntimeHelpers.GetHashCode(object)以及它是如何工作的呢?它是如何计算哈希的?

4

4 回答 4

28

我认为 MSDN 文档试图描述行为,而不是实现。关键点:RuntimeHelpers返回您将获得的默认实现object.GetHashCode() 未被覆盖。

例如,如果您想构建一个引用相等查找,这非常有用,即使对于已覆盖Equalsand的类型也是如此GetHashCode。我在我维护的序列化程序中执行此操作,使用RuntimeHelpers.GetHashCode()and Object.ReferenceEquals

于 2012-06-28T07:39:43.447 回答
11

关键是object.GetHashCode()可以覆盖 - 并且经常是,例如通过string. 这意味着您无法找到默认实现object.GetHashCode()返回的“身份哈希码”。

如果您想实现一个只考虑对象身份的相等比较器(例如,对于 a HashSet),这可能很有用。

例如:

public class IdentityComparer<T> : IEqualityComparer<T> where T : class
{
    public bool Equals(T x, T y)
    {
        // Just for clarity...
        return object.ReferenceEquals(x, y);
    }

    public int GetHashCode(T x)
    {
        // The nullity check may be unnecessary due to a similar check in
        // RuntimeHelpers.GetHashCode, but it's not documented
        return x == null ? 0 : RuntimeHelpers.GetHashCode(x);
    }
}

然后:

string x = "hello";
string y = new StringBuilder("h").Append("ello").ToString();
Console.WriteLine(x == y); // True (overloaded ==)
Console.WriteLine(x.GetHashCode() == y.GetHashCode()); // True (overridden)

IdentityComparer<string> comparer = new IdentityComparer<string>();
Console.WriteLine(comparer.Equals(x, y)); // False - not identity

// Very probably false; not absolutely guaranteed (as ever, collisions
// are possible)
Console.WriteLine(comparer.GetHashCode(x) == comparer.GetHashCode(y));

编辑:只是为了澄清一点......

那么 RuntimeHelpers.GetHashCode(object) 的实际行为是什么,它是如何工作的?

观察到的行为是从返回RuntimeHelpers.GetHashCode(object)的值与从非虚拟调用返回的值相同Object.GetHashCode()。(你不能轻易地用 C# 编写那个非虚拟调用。)

至于它是如何工作的 - 这是一个实现细节:) IMO 以哪种方式发生事情并不重要(什么叫什么)。重要的是记录在案的行为,这是正确的。哎呀,不同版本的 mscorlib 可以以不同的方式实现这一点——从用户的角度来看,这根本不重要。如果没有反编译,您应该无法区分。

如果Object.GetHashCodeRuntimeHelpers.GetHashCode().

于 2012-06-28T07:40:46.280 回答
4

奇怪,当我通过 Reflector 查看 System.Object.GetHashCode 时,我看到了

public virtual int GetHashCode()
{
    return InternalGetHashCode(this);
}

对于运行时助手:

public static int GetHashCode(object o)
{
    return object.InternalGetHashCode(o);
}

也许这是一个框架差异?我正在查看 2.0 程序集。

于 2012-06-28T07:39:18.153 回答
0

从您自己的问题来看,看起来RuntimeHelpers.GetHashCode(Object)确实是 non-overridden 的实现Object.GetHashCode()

于 2012-06-28T07:40:17.777 回答