当两个相同类型的对象具有相同的值时,为什么哈希码不同?

时间:2013-04-04 17:14:26

标签: c# .net gethashcode

据我了解,GetHashCode将为两个共享相同值的不同实例返回相同的值。在这一点上,MSDN文档有点模糊。

  

哈希码是用于标识对象的数值   在平等测试期间。

如果我有两个相同类型且具有相同值的实例,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
}

5 个答案:

答案 0 :(得分:8)

框架为您的自定义对象计算的哈希代码不能保证完全相同。

我认为这是因为框架没有走遍你所有的领域而且计算他们的哈希码,对每个对象来说这都是一件非常耗时的事情(我可能错了)。

这就是为什么建议您覆盖自己类型的Equals()GetHashCode()方法。

请参阅:Overriding GetHashCode

答案 1 :(得分:3)

如果类SecurityUser存储为您创建的每个用户增加的ID,则它们可能会有所不同。如果类使用它来计算它的HashCode,它们可能会有所不同。您不应该依赖GetHashCode来测试两个对象之间的相等性。

GetHashCode的唯一要求是objA.Equals(objB),然后是objA.GetHashCode() == objB.GetHashCode()

有关GetHashCode()实施的详细信息,请参阅this link(“实施者须知”部分),尤其是本段:

  
      
  • 如果两个对象比较相等,则为每个对象提供GetHashCode方法   对象必须返回相同的值。但是,如果两个对象没有   比较相同,两个对象的GetHashCode方法不相同   必须返回不同的值。
  •   

如果GetHashCode()中的SecurityUser 未被覆盖,则两个HashCodes会有所不同,因为两个对象objAobjB是对内存中的不同对象(如new - 关键字所示)。

答案 2 :(得分:3)

来自MSDN

  

GetHashCode方法的默认实现没有   保证不同对象的唯一返回值。而且,   .NET Framework不保证默认的实现   GetHashCode方法,它返回的值将是相同的   不同版本的.NET Framework。因此,默认   不得将此方法的实现用作唯一对象   用于散列目的的标识符。

     

GetHashCode方法可以被派生类型覆盖。值   类型必须覆盖此方法以提供哈希函数   适合该类型并在a中提供有用的分布   哈希表。为了唯一性,哈希码必须基于值   实例字段或属性而不是静态字段或   属性。

这意味着您应该覆盖班级中的GetHashCode

答案 3 :(得分:1)

C#中的HashCodes并不像它们看起来那么简单。默认情况下,类不会为两个相同的实例返回相同的哈希码,您必须自己创建该行为。在特定场景中使用散列码来优化查找,但至少有一位创始开发人员说过,如果他们有机会重新开始并重新开始,那么GetHashCode()就不会成为基础对象方法之一。 / p>

答案 4 :(得分:1)

在值类型上,GetHashCode()将为具有相同值的两个对象返回相同的哈希值。但是SecurityUser是一个引用类型,因此,它的默认GetHashCode()方法(继承自System.Object,正如其他人提到的那样)返回基于对象引用的哈希。由于SecurityUser的两个不同实例不共享相同的引用,因此它们不共享相同的哈希代码。

您可以通过覆盖GetHashCode()中的SecurityUser方法来覆盖此行为,以便计算类的成员而不是类本身的哈希值。确保您也覆盖Equals(),因为这两种方法是齐头并进的。您也可以考虑重写==等于运算符。

请参阅本文中接受的答案,了解GetHashCode()的实施示例:What is the best algorithm for an overridden System.Object.GetHashCode?