この記事では、この API のリファレンス ドキュメントに補足的な解説を提供します。
RuntimeHelpers.GetHashCode メソッドは、オブジェクトの型が Object.GetHashCode メソッドをオーバーライドした場合でも、常に仮想的にObject.GetHashCode メソッドを呼び出します。 したがって、RuntimeHelpers.GetHashCodeを使用すると、Object.GetHashCode メソッドを使用してオブジェクトで直接GetHashCode
を呼び出すのとは異なる場合があります。
Warnung
RuntimeHelpers.GetHashCode メソッドは同一のオブジェクト参照に対して同一のハッシュ コードを返しますが、このハッシュ コードはオブジェクト参照を一意に識別しないため、このメソッドを使用してオブジェクト ID をテストしないでください。 オブジェクト ID をテストするには (つまり、2 つのオブジェクトがメモリ内の同じオブジェクトを参照していることをテストするために)、 Object.ReferenceEquals メソッドを呼び出します。 また、 GetHashCode を使用して、2 つの文字列が等しいオブジェクト参照を表しているかどうかをテストする必要もありません。これは、文字列がインターンされているためです。 文字列のインターンをテストするには、 String.IsInterned メソッドを呼び出します。
Object.GetHashCodeとRuntimeHelpers.GetHashCodeの方法は次のように異なります。
- Object.GetHashCode は、オブジェクトの等値の定義に基づくハッシュ コードを返します。 たとえば、内容が同じ 2 つの文字列は、 Object.GetHashCodeに対して同じ値を返します。
- RuntimeHelpers.GetHashCode は、オブジェクト ID を示すハッシュ コードを返します。 つまり、内容が同じで、インターンされた文字列を表す 2 つの文字列変数 ( 「String Interning 」セクションを参照) またはメモリ内の 1 つの文字列を表す 2 つの文字列変数は、同じハッシュ コードを返します。
Von Bedeutung
GetHashCodeは、等しいオブジェクト参照に対して常に同じハッシュ コードを返します。 ただし、逆は true ではありません。等しいハッシュ コードは、等しいオブジェクト参照を示しません。 特定のハッシュ コード値は、特定のオブジェクト参照に対して一意ではありません。異なるオブジェクト参照によって同じハッシュ コードが生成される場合があります。
このメソッドはコンパイラによって使用されます。
文字列のインターン
共通言語ランタイム (CLR) は、文字列の内部プールを保持し、リテラルをプールに格納します。 同じ文字列リテラルから 2 つの文字列 (たとえば、 str1
と str2
) が形成されている場合、CLR は、メモリを節約するために、マネージド ヒープ上の同じ場所を指す str1
と str2
を設定します。 これら 2 つの文字列オブジェクトに対して RuntimeHelpers.GetHashCode を呼び出すと、前のセクションの 2 番目の箇条書き項目とは異なり、同じハッシュ コードが生成されます。
CLR は、リテラルのみをプールに追加します。 連結などの文字列操作の結果は、コンパイラが文字列連結を単一の文字列リテラルとして解決しない限り、プールには追加されません。 したがって、連結操作の結果として str2
が作成され、 str2
が str1
と同じである場合、これら 2 つの文字列オブジェクトで RuntimeHelpers.GetHashCode を使用しても、同じハッシュ コードは生成されません。
連結された文字列をプールに明示的に追加する場合は、 String.Intern メソッドを使用します。
String.IsInternedメソッドを使用して、文字列にインターン参照があるかどうかを確認することもできます。
例示
次の例では、 Object.GetHashCode メソッドと RuntimeHelpers.GetHashCode メソッドの違いを示します。 この例からの出力は、次の例を示しています。
ShowHashCodes
メソッドに渡される文字列の最初のセットのハッシュ コードのセットは、文字列が完全に異なるため、両方とも異なります。Object.GetHashCode は、文字列が等しいため、
ShowHashCodes
メソッドに渡される 2 番目の文字列セットに対して同じハッシュ コードを生成します。 ただし、 RuntimeHelpers.GetHashCode メソッドには対応していません。 最初の文字列は文字列リテラルを使用して定義されるため、強制されます。 2 番目の文字列の値は同じですが、 String.Format メソッドの呼び出しによって返されるため、インターンされません。3 番目の文字列の場合、両方の文字列の Object.GetHashCode によって生成されるハッシュ コードは、 RuntimeHelpers.GetHashCodeによって生成されるハッシュ コードと同じです。 これは、コンパイラが両方の文字列に割り当てられた値を 1 つの文字列リテラルとして扱い、文字列変数が同じインターン文字列を参照するためです。
using System;
using System.Runtime.CompilerServices;
public class Example
{
public static void Main()
{
Console.WriteLine("{0,-18} {1,6} {2,18:N0} {3,6} {4,18:N0}\n",
"", "Var 1", "Hash Code", "Var 2", "Hash Code");
// Get hash codes of two different strings.
String sc1 = "String #1";
String sc2 = "String #2";
ShowHashCodes("sc1", sc1, "sc2", sc2);
// Get hash codes of two identical non-interned strings.
String s1 = "This string";
String s2 = String.Format("{0} {1}", "This", "string");
ShowHashCodes("s1", s1, "s2", s2);
// Get hash codes of two (evidently concatenated) strings.
String si1 = "This is a string!";
String si2 = "This " + "is " + "a " + "string!";
ShowHashCodes("si1", si1, "si2", si2);
}
private static void ShowHashCodes(String var1, Object value1,
String var2, Object value2)
{
Console.WriteLine("{0,-18} {1,6} {2,18:X8} {3,6} {4,18:X8}",
"Obj.GetHashCode", var1, value1.GetHashCode(),
var2, value2.GetHashCode());
Console.WriteLine("{0,-18} {1,6} {2,18:X8} {3,6} {4,18:X8}\n",
"RTH.GetHashCode", var1, RuntimeHelpers.GetHashCode(value1),
var2, RuntimeHelpers.GetHashCode(value2));
}
}
// The example displays output similar to the following:
// Var 1 Hash Code Var 2 Hash Code
//
// Obj.GetHashCode sc1 94EABD27 sc2 94EABD24
// RTH.GetHashCode sc1 02BF8098 sc2 00BB8560
//
// Obj.GetHashCode s1 29C5A397 s2 29C5A397
// RTH.GetHashCode s1 0297B065 s2 03553390
//
// Obj.GetHashCode si1 941BCEA5 si2 941BCEA5
// RTH.GetHashCode si1 01FED012 si2 01FED012
Imports System.Runtime.CompilerServices
Module Example
Public Sub Main()
Console.WriteLine("{0,-18} {1,6} {2,18:N0} {3,6} {4,18:N0}",
"", "Var 1", "Hash Code", "Var 2", "Hash Code")
Console.WriteLine()
' Get hash codes of two different strings.
Dim sc1 As String = "String #1"
Dim sc2 As String = "String #2"
ShowHashCodes("sc1", sc1, "sc2", sc2)
' Get hash codes of two identical non-interned strings.
Dim s1 As String = "This string"
Dim s2 As String = String.Format("{0} {1}", "This", "string")
ShowHashCodes("s1", s1, "s2", s2)
' Get hash codes of two (evidently concatenated) strings.
Dim si1 As String = "This is a string!"
Dim si2 As String = "This " + "is " + "a " + "string!"
ShowHashCodes("si1", si1, "si2", si2)
End Sub
Private Sub ShowHashCodes(var1 As String, value1 As Object,
var2 As String, value2 As Object)
Console.WriteLine("{0,-18} {1,6} {2,18:X8} {3,6} {4,18:X8}",
"Obj.GetHashCode", var1, value1.GetHashCode,
var2, value2.GetHashCode)
Console.WriteLine("{0,-18} {1,6} {2,18:X8} {3,6} {4,18:X8}",
"RTH.GetHashCode", var1, RuntimeHelpers.GetHashCode(value1),
var2, RuntimeHelpers.GetHashCode(value2))
Console.WriteLine()
End Sub
End Module
' The example displays output similar to the following:
' Var 1 Hash Code Var 2 Hash Code
'
' Obj.GetHashCode sc1 94EABD27 sc2 94EABD24
' RTH.GetHashCode sc1 02BF8098 sc2 00BB8560
'
' Obj.GetHashCode s1 29C5A397 s2 29C5A397
' RTH.GetHashCode s1 0297B065 s2 03553390
'
' Obj.GetHashCode si1 941BCEA5 si2 941BCEA5
' RTH.GetHashCode si1 01FED012 si2 01FED012
.NET