RuntimeHelpers.GetHashCode做了什么

时间:2012-06-28 07:33:58

标签: c# .net clr base-class-library

RuntimeHelpers.GetHashCode(object)方法允许根据对象的标识生成哈希码。 MSDN states

  

RuntimeHelpers.GetHashCode方法总是调用   Object.GetHashCode方法非虚拟化,即使对象的类型具有   重写了Object.GetHashCode方法。

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

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

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

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

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

4 个答案:

答案 0 :(得分:23)

我认为MSDN文档试图描述行为,而不是实现。关键点:RuntimeHelpers会返回默认实施,如果object.GetHashCode() 重写,您将获得此实现。

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

答案 1 :(得分:11)

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

如果您想要实现一个认为是对象标识的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(对象)的实际行为是什么?它是如何工作的?

观察到的行为是RuntimeHelpers.GetHashCode(object)返回的值与从Object.GetHashCode()的非虚拟调用返回的值相同。 (您无法轻松地在C#中编写非虚拟调用。)

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

({1}} Object.GetHashCodeRuntimeHelpers.GetHashCode()进行记录会使(IMO)更加困惑。

答案 2 :(得分:4)

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

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

和runtimehelper:

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

也许这是一个框架差异?我正在看2.0组件。

答案 3 :(得分:0)

从您自己的问题来看,RuntimeHelpers.GetHashCode(Object)实际上是非覆盖Object.GetHashCode()的实现。