4

据我了解,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
}
4

5 回答 5

6

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

我相信这是由于框架没有遍历所有字段等并计算它们的哈希码,这对每个对象来说都是一件非常耗时的事情(我可能错了)。

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

请参阅:覆盖 GetHashCode

于 2013-04-04T17:16:10.670 回答
4

来自MSDN

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

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

这意味着你应该GetHashCode在你的类中重写。

于 2013-04-04T17:20:50.127 回答
3

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

的唯一要求GetHashCode是 if objA.Equals(objB),then objA.GetHashCode() == objB.GetHashCode()

有关 的实施的详细信息,尤其是本段,请参阅此链接(“实施者注意事项”部分) :GetHashCode()

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

如果GetHashCode()中覆盖SecurityUser,则两个 HashCode 将作为两个对象不同,objA并且objB是对内存中不同对象的引用(如new-Keyword 所示)。

于 2013-04-04T17:18:50.980 回答
2

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

于 2013-04-04T17:21:52.913 回答
2

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

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

有关以下实现的一个很好的示例,请参阅这篇文章中接受的答案GetHashCode()什么是覆盖 System.Object.GetHashCode 的最佳算法?

于 2013-04-07T16:52:15.870 回答