2013-04-04 6 views
2

Насколько я понимаю, GetHashCode вернет одно и то же значение для двух разных экземпляров, которые имеют одинаковые значения. В этом случае документация MSDN немного нечеткая.Почему хэш-коды разные, если два объекта одного типа имеют одинаковые значения?

Хэш-код - это числовое значение, которое используется для идентификации объекта во время проверки равенства.

Если у меня есть два экземпляра одного и того же типа, и те же значения будут возвращать значение GetHashCode()?

Предполагая, что все значения совпадают, будет ли следующий тест прошлым или неудачным?

SecurityUser имеет только приемники и сеттеры;

[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' может быть переопределен в производных классах, чтобы возвращать что-либо. Нет никакой гарантии, что его реализация верна. –

+0

@RobertHarvey Неплохо, я должен был указать, это не так. SecurityUser имеет только получатели и сеттеры. –

ответ

7

Хеш-коды, рассчитанные каркасом для ваших заказных объектов, не гарантируются.

Я считаю, что это связано с тем, что каркас, не ходящий по всем вашим полям и т.п., и вычисляющий их хэш-коды, для каждого объекта может быть такой дорогостоящей задачей (я могу ошибаться).

Именно поэтому рекомендуется переопределить методы Equals() и GetHashCode() на свои собственные типы.

См: Overriding GetHashCode

+7

Хэш-код, сгенерированный, когда вы не переопределяете 'GetHashCode', является' object.GetHashCode', который просто возвращает определенный CLR номер на основе ссылки. –

+1

@JasonWatkins Я действительно считал, что это так, и это по умолчанию было для System.Object, но я не был достаточно уверен, чтобы заявить как таковой: P – Clint

+1

@JasonWatkins Хорошо, это имеет смысл. Если создать два пустых объекта того же типа, они будут (всегда, по большей части) возвращать разные значения. –

2

Они могут быть разными, если класс SecurityUser хранит идентификатор, который увеличивает для каждого пользователя вы создаете. Если класс использует это для вычисления HashCode, они, вероятно, будут отличаться. Вы не должны полагаться на GetHashCode для проверки равенства между двумя объектами.

Единственным требованием для GetHashCode является то, что если objA.Equals(objB), то objA.GetHashCode() == objB.GetHashCode().

См this link (раздел «Примечания реализаторам») для получения подробной информации об осуществлении GetHashCode(), особенно этот пункт:

  • Если два объекта сравниваются как равные, метод GetHashCode для каждого объекта должен вернуться такое же значение. Однако, если два объекта не сравнить как равные, методы GetHashCode для двух объектов не должны возвращать разные значения.

Если GetHashCode() является не переопределен в SecurityUser, два HashCodes будет отличаться, как два объекта objA и objB ссылки на различные объекты в памяти (как обозначено new -ключевое слово).

3

MSDN От:

Реализация по умолчанию методы GetHashCode не гарантии уникальных возвращаемых значений для различных объектов. Кроме того, .NET Framework не гарантирует реализацию по умолчанию метода GetHashCode по умолчанию, а возвращаемое значение будет одинаковым между различными версиями .NET Framework. Следовательно, реализация этого метода по умолчанию не должна использоваться как уникальный объект идентификатор для целей хэширования.

Метод GetHashCode может быть переопределен производным типом. Значения типы должны переопределять этот метод, чтобы обеспечить хеш-функцию, которая соответствует , для этого типа, и обеспечить полезное распределение в хеш-таблице . Для уникальности хэш-код должен быть основан на значении поля или свойства экземпляра вместо статического поля или свойства .

Это значит, что вы должны переопределить GetHashCode в своем классе.

+1

+1 для текста из MSDN. – Clint

1

HashCodes на C# не так просты, как могут показаться. По умолчанию класс не будет возвращать один и тот же хэш-код для двух одинаковых экземпляров, вы должны сами создать это поведение. Хэш-коды используются в определенных сценариях для оптимизации поиска, но, по крайней мере, один из разработчиков-разработчиков сказал, что если бы у них была возможность вернуться и начать, GetHashCode() не был бы одним из методов базовых объектов.

+0

Я забыл, что GetHashCode() на самом деле object.GetHashCode() –

1

На тип значения GetHashCode() вернет тот же хэш для двух объектов одного и того же значения. Однако SecurityUser является ссылочным типом и как таковой, его метод по умолчанию GetHashCode() (унаследованный от System.Object, как упоминалось в других публикациях) возвращает хэш на основе ссылки объекта. Поскольку два разных экземпляра SecurityUser не используют одну и ту же ссылку, они не используют один и тот же хэш-код.

Вы можете переопределить это поведение путем переопределения метода GetHashCode() в SecurityUser так, чтобы вычислить хэш Офф-членов вашего класса, а не из самого класса. Удостоверьтесь, что вы также переопределили Equals(), так как эти два метода идут рука об руку. Вы также можете рассмотреть возможность переопределения оператора равенства.

Смотрите принятый ответ на этот пост для хорошего примера реализации GetHashCode(): What is the best algorithm for an overridden System.Object.GetHashCode?

 Смежные вопросы

  • Нет связанных вопросов^_^