2013-04-04 135 views
2

我的理解是,GetHashCode將爲共享相同值的兩個不同實例返回相同的值。 MSDN文檔在這一點上有點模糊。當兩個相同類型的對象具有相同的值時,爲什麼hashcode不同?

哈希碼是一個數值,用於在進行相等測試期間識別對象 。

如果我有兩個相同類型的實例和相同的值將GetHashCode()返回相同的值?

假設所有的值都是一樣的,下面的測試過去還是失敗?

SecurityUser只有getter和setter;

[TestMethod] 
    public void GetHashCode_Equal_Test() 
    { 
     SecurityUser objA = new SecurityUser(EmployeeName, EmployeeNumber, LastLogOnDate, Status, UserName); 
     SecurityUser objB = new SecurityUser(EmployeeName, EmployeeNumber, LastLogOnDate, Status, UserName); 

     int hashcodeA = objA.GetHashCode(); 
     int hashcodeB = objB.GetHashCode(); 

     Assert.AreEqual<int>(hashcodeA, hashcodeB); 
    } 


/// <summary> 
/// This class represents a SecurityUser entity in AppSecurity. 
/// </summary> 
public sealed class SecurityUser 
{ 
    #region [Constructor] 

    /// <summary> 
    /// Initializes a new instance of the <see cref="SecurityUser"/> class using the 
    /// parameters passed. 
    /// </summary> 
    /// <param name="employeeName">The employee name to initialize with.</param> 
    /// <param name="employeeNumber">The employee id number to initialize with.</param> 
    /// <param name="lastLogOnDate">The last logon date to initialize with.</param> 
    /// <param name="status">The <see cref="SecurityStatus"/> to initialize with.</param> 
    /// <param name="userName">The userName to initialize with.</param>   
    public SecurityUser(
     string employeeName, 
     int employeeNumber,    
     DateTime? lastLogOnDate, 
     SecurityStatus status, 
     string userName) 
    { 
     if (employeeName == null) 
      throw new ArgumentNullException("employeeName"); 

     if (userName == null) 
      throw new ArgumentNullException("userName"); 

     this.EmployeeName = employeeName; 
     this.EmployeeNumber = employeeNumber; 
     this.LastLogOnDate = lastLogOnDate; 
     this.Status = status; 
     this.UserName = userName; 
    } 

    #endregion 

    #region [Properties] 

    /// <summary> 
    /// Gets the employee name of the current instance. 
    /// </summary> 
    public string EmployeeName { get; private set; } 

    /// <summary> 
    /// Gets the employee id number of the current instance. 
    /// </summary> 
    public int EmployeeNumber { get; private set; } 

    /// <summary> 
    /// Gets the last logon date of the current instance. 
    /// </summary> 
    public DateTime? LastLogOnDate { get; private set; } 

    /// <summary> 
    /// Gets the userName of the current instance. 
    /// </summary> 
    public string UserName { get; private set; } 

    /// <summary> 
    /// Gets the <see cref="SecurityStatus"/> of the current instance. 
    /// </summary> 
    public SecurityStatus Status { get; private set; } 

    #endregion 
} 
+3

哪裏了'SecurityUser'類從何而來?可以在派生類中重寫'GetHashCode'來返回任何東西。不能保證其實施是正確的。 – 2013-04-04 17:17:53

+0

@RobertHarvey我不好,我應該指出,它不。 SecurityUser只有getter和setter。 – 2013-04-04 17:19:48

回答

7

框架爲您的自定義對象計算的散列碼不保證是相同的。

我相信這是由於框架沒有走過你的所有領域,並計算它們的hashcode,對於每個對象(我可能是錯的),這將是一個耗時的事情。

這就是爲什麼建議您在自己的類型上覆蓋Equals()GetHashCode()方法的原因。

參見:Overriding GetHashCode

+7

當您不重寫'GetHashCode'時生成的哈希碼是'object.GetHashCode',它只是基於參考返回一個CLR確定的數字。 – 2013-04-04 17:20:27

+1

@JasonWatkins我確實相信是這種情況,它默認爲System.Object,但我不確定如此陳述:P – Clint 2013-04-04 17:21:06

+1

@JasonWatkins好的,這是有道理的。如果創建兩個相同類型的空對象,它們將(總是大部分)返回不同的值。 – 2013-04-04 17:24:14

2

他們可能是不同的,如果該類​​商店爲你創建的每個用戶增加一個ID。如果這個類使用它來計算它的HashCode,它們可能會不同。您不應該依賴GetHashCode來測試兩個對象之間的相等性。

GetHashCode的唯一要求是,如果objA.Equals(objB),那麼objA.GetHashCode() == objB.GetHashCode()

詳見this link(節「給實現」)上的GetHashCode()的實施,特別是這一段:

  • 如果兩個對象的比較結果相等,每個 對象GetHashCode方法必須返回相同的價值。但是,如果兩個對象 的比較結果不相等,則兩個對象的GetHashCode方法不需要 必須返回不同的值。

如果GetHashCode()重寫在​​,這兩個散列碼將是不同的,因爲這兩個對象objAobjB和在存儲器中的不同對象的引用(由new - 關鍵字所指示的)。

3

MSDN

GetHashCode方法的默認實現不執行對不同的對象不 保證唯一的返回值。此外, 。NET框架不保證 GetHashCode方法的默認實現,並且它返回的值將在 不同版本的.NET Framework之間相同。因此,不得將此方法的默認實現用作散列目的的唯一對象 標識符。

GetHashCode方法可以被派生類型覆蓋。值 類型必須重寫此方法以提供適用於該類型的散列函數 並在散列表中提供有用的分佈。爲了唯一性,哈希碼必須基於實例字段或屬性的值 而不是靜態字段或 屬性。

這意味着您應該在班級中覆蓋GetHashCode

+1

對於來自MSDN的文本+1。 – Clint 2013-04-04 17:21:45

1

C#中的HashCode並不像它們可能出現的那樣直截了當。默認情況下,一個類不會爲兩個相同的實例返回相同的哈希碼,您必須自己創建該行爲。在特定場景中使用哈希代碼來優化查找,但至少有一位創始開發人員表示,如果他們有機會重新開始並重新開始,GetHashCode()將不會成爲基礎對象方法之一。

+0

我忘記了GetHashCode()實際上是object.GetHashCode() – 2013-04-04 17:27:29

1

在值類型上,GetHashCode()將爲相同值的兩個對象返回相同的散列值。然而​​是一個引用類型,因此它的默認GetHashCode()方法(從其他人提到的System.Object繼承)返回一個基於對象引用的散列。由於​​的兩個不同實例不共享相同的引用,因此它們不共享相同的哈希碼。

您可以通過覆蓋在​​的GetHashCode()方法,以計算散列關閉成員類而不是類本身的覆蓋此行爲。確保你也覆蓋Equals(),因爲這兩種方法齊頭並進。你也可以考慮重寫==等號運算符。

見在這個崗位接受的答案爲GetHashCode()實現的一個很好的例子:What is the best algorithm for an overridden System.Object.GetHashCode?

相關問題