25

このRuntimeHelpers.GetHashCode(object)メソッドを使用すると、オブジェクトの ID に基づいてハッシュ コードを生成できます。MSDNの状態:

オブジェクトのタイプが Object.GetHashCode メソッドをオーバーライドした場合でも、RuntimeHelpers.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);
}

Object.GetHashCode内部から呼び出すRuntimeHelpers.GetHashCode(object)とスタック オーバーフローが発生するため、MSDN のドキュメントが間違っていると思われます。

では、実際の動作はどのようなものでRuntimeHelpers.GetHashCode(object)、どのように機能するのでしょうか? ハッシュはどのように計算されますか?

4

4 に答える 4

28

MSDN のドキュメントは、実装ではなく動作を説明しようとしていると思います。重要なポイント:オーバーライドされていないデフォルトの実装をRuntimeHelpers返します。object.GetHashCode()

これは、たとえば、オーバーライドされた型EqualsGetHashCode. 私が維持しているシリアライザーでこれを行い、 と を使用RuntimeHelpers.GetHashCode()Object.ReferenceEqualsます。

于 2012-06-28T07:39:43.447 に答える
11

ポイントは、object.GetHashCode()オーバーライドできることです-そして、多くの場合、string. つまり、デフォルトの実装がobject.GetHashCode()返す「ID ハッシュ コード」を見つけることができません。

これは、オブジェクトの同一性のみを考慮する等価比較子 (たとえば aHashSetなど)を実装する場合に役立ちます。

例えば:

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.GetHashCode(IMO)の観点から文書化されていたのは、はるかに混乱していたでしょうRuntimeHelpers.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)実際には非オーバーライドの実装のようですObject.GetHashCode()

于 2012-06-28T07:40:17.777 に答える