System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode 方法

本文提供了此 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 将设置 str1str2 指向托管堆上的同一位置以节省内存。 调用这两个字符串对象上的 RuntimeHelpers.GetHashCode 将生成相同的哈希值,这与上一部分中的第二个项目符号项相反。

CLR 仅将文本添加到池中。 除非编译器将字符串连接解析为单个字符串字面量,否则连接等字符串操作的结果不会被添加到池中。 因此,如果 str2 是串联操作的结果,并且 str2str1 相同,那么在这两个字符串对象上使用 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