本文提供了此 API 参考文档的补充说明。
RuntimeHelpers.GetHashCode 方法始终以非虚拟方式调用 Object.GetHashCode 方法,即使对象的类型已重写 Object.GetHashCode 方法。 因此,使用 RuntimeHelpers.GetHashCode 可能与使用 GetHashCode
方法直接在对象上调用 Object.GetHashCode 不同。
警告
RuntimeHelpers.GetHashCode尽管该方法为相同的对象引用返回相同的哈希代码,但不应使用此方法测试对象标识,因为此哈希代码不会唯一标识对象引用。 若要测试对象标识(即测试两个对象在内存中引用同一对象),请调用该方法 Object.ReferenceEquals 。 也不应该使用 GetHashCode 来测试两个字符串是否代表相等的对象引用,因为该字符串是驻留的。 若要测试字符串驻留,请调用String.IsInterned方法。
Object.GetHashCode方法与RuntimeHelpers.GetHashCode方法的区别如下:
- Object.GetHashCode 返回一个哈希代码,该代码基于对象的相等性定义。 例如,包含相同内容的两个字符串将返回相同的值 Object.GetHashCode。
- RuntimeHelpers.GetHashCode 返回指示对象标识的哈希代码。 也就是说,两个字符串变量的内容相同,而且表示一个驻留的字符串(请参阅 字符串驻留 部分)或表示内存中的单个字符串时,它们将返回相同的哈希代码。
重要
请注意, GetHashCode 始终返回相同对象引用的相同哈希代码。 但是,反向不是真的:相等哈希代码不指示相等的对象引用。 特定哈希代码值对特定对象引用不是唯一的;不同的对象引用可以生成相同的哈希代码。
编译器使用此方法。
字符串驻留
公共语言运行时(CLR)维护一个字符串的内部池,并将字面值存储在该池中。 如果两个字符串(例如 str1
,和 str2
)是从相同的字符串文本构成的,则 CLR 将设置 str1
并 str2
指向托管堆上的同一位置以节省内存。 调用这两个字符串对象上的 RuntimeHelpers.GetHashCode 将生成相同的哈希值,这与上一部分中的第二个项目符号项相反。
CLR 仅将文本添加到池中。 除非编译器将字符串连接解析为单个字符串字面量,否则连接等字符串操作的结果不会被添加到池中。 因此,如果 str2
是串联操作的结果,并且 str2
与 str1
相同,那么在这两个字符串对象上使用 RuntimeHelpers.GetHashCode 将不会产生相同的哈希代码。
如果要显式向池添加串联字符串,请使用 String.Intern 该方法。
还可以使用 String.IsInterned 方法来检查字符串是否具有驻留引用。
例子
以下示例演示了 Object.GetHashCode 方法 RuntimeHelpers.GetHashCode 之间的差异。 该示例的输出演示了以下内容:
传递给
ShowHashCodes
该方法的第一组字符串的两组哈希代码都是不同的,因为字符串完全不同。Object.GetHashCode 为传递给
ShowHashCodes
方法的第二组字符串生成相同的哈希代码,因为字符串相等。 但是,该方法 RuntimeHelpers.GetHashCode 不起作用。 第一个字符串是使用字符串字面量定义的,因此是驻留的。 尽管第二个字符串的值相同,但它并未被驻留,因为它是通过调用 String.Format 方法返回的。对于第三个字符串,由 Object.GetHashCode 生成的哈希代码与由 RuntimeHelpers.GetHashCode 生成的哈希代码相同。 这是因为编译器将分配给这两个字符串的值视为单个字符串常量,因此字符串变量引用同一个驻留字符串。
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