2013-04-04 98 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?

相关问题