2013-04-11 2 views
1

Существует отрывок из NHibernate документации:Implemeting GetHashCode и Equals методы ValueObjects

Примечание: если вы определяете ISet составных элементов, очень важно для реализации Equals() и GetHashCode() правильно.

Что такое correctly означает, что там? Нужно ли реализовать эти методы для всех объектов значений в домене?

РАСШИРЕНИЕ МОЙ ВОПРОС

В статье Марк прилагается пользователь Albic состояния:

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

Я, наконец, нашел решение этой проблемы, когда я работал с NHibernate. Мой подход заключается в вычислении хеш-кода из идентификатора объекта. Идентификатор может быть установлен только с помощью конструктора, поэтому, если вы хотите изменить ID, что очень маловероятно, вам нужно создать новый объект с новым идентификатором и, следовательно, новый хэш-код. Этот подход лучше всего работает с GUID, потому что вы можете предоставить конструктор без параметров, который случайным образом генерирует идентификатор.

я вдруг понял, что у меня есть в моем AbstractEntity классе:

public abstract class AbstractEntity<T> where T : AbstractEntity<T> { 
    private Nullable<Int32> hashCode; 

    public virtual Guid Id { get; protected set; } 
    public virtual Byte[] Version { get; set; } 

    public override Boolean Equals(Object obj) { 
     var other = obj as T; 
     if(other == null) { 
      return false; 
     } 

     var thisIsNew = Equals(this.Id, Guid.Empty); 
     var otherIsNew = Equals(other.Id, Guid.Empty); 

     if(thisIsNew && otherIsNew) { 
      return ReferenceEquals(this, other); 
     } 

     return this.Id.Equals(other.Id); 
    } // public override Boolean Equals(Object obj) { 

    public override Int32 GetHashCode() { 
     if(this.hashCode.HasValue) { 
      return this.hashCode.Value; 
     } 

     var thisIsNew = Equals(this.Id, Guid.Empty); 
     if(thisIsNew) { 
      this.hashCode = base.GetHashCode(); 
      return this.hashCode.Value; 
     } 
     return this.Id.GetHashCode(); 
    } // public override Int32 GetHashCode() { 

    public static Boolean operator ==(AbstractEntity<T> l, AbstractEntity<T> r) { 
     return Equals(l, r); 
    } 
    public static Boolean operator !=(AbstractEntity<T> l, AbstractEntity<T> r) { 
     return !Equals(l, r); 
    } 
} // public abstract class AbstractEntity<T>... 

Поскольку все components вложены в entities я должен затем реализовать Equals() и GetHashCode() для них?

+1

Связанный: http://stackoverflow.com/questions/371328/why-is-it-important-to-override-gethashcode-when-equals-method-is-overridden?rq=1 –

ответ

1

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

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

+0

следует ли это применять только к «компонентам» в наборах или ко всем «компонентам» («объектам ценности») в домене? – lexeme

+1

Учитывая, что GetHashCode обычно представляет потерю верности (то есть больше данных кодируется в объекте, чем в результирующем 32-битном хэше), вы не можете гарантировать уникальность хэш-кода для неравных объектов. Эрго, ваш последний пункт неверен. Столкновения в хэшах неизбежны (если вы не хешируете что-то, несущее меньше или равно 32 бит информации, и вы готовите идеальный хеш) – spender

+0

это зависит от * логики * вашего приложения. Итак, логика: make gethashcode возвращает одно и то же значение для всех компонентов, которые в * вашей * системе должны быть recoginzed как равные. Пример: если я смотрю на специалистов, врач и водитель не равны, если я смотрю с точки зрения биологии, они * равны (оба человека). Это зависит от того, как должно работать приложение * yuor *. – Tigran

1

В документации для Equals и GetHashCode объясните эту ситуацию и укажите конкретные рекомендации по реализации объектов значений. Для объектов значений Equals имеет значение true, если объекты одного типа, а общие и частные поля равны. Однако это объяснение относится к типам значений структуры, и вы можете создавать свои собственные Equals, переопределяя их.

GetHashCode имеет два правила, которые необходимо соблюдать:

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

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