Я часто переопределяю Equals()
и GetHashCode()
, чтобы реализовать семантику, согласно которой бизнес-объекты с одинаковыми значениями свойств равны.Это приводит к тому, что код является повторяющимся для написания и хрупким для поддержки (свойство добавляется, и одно / оба переопределения не обновляются).
В конечном итоге код выглядит примерно так (комментарии к реализации приветствуются):
public override bool Equals(object obj)
{
if (object.ReferenceEquals(this, obj)) return true;
MyDerived other = obj as MyDerived;
if (other == null) return false;
bool baseEquals = base.Equals((MyBase)other);
return (baseEquals &&
this.MyIntProp == other.MyIntProp &&
this.MyStringProp == other.MyStringProp &&
this.MyCollectionProp.IsEquivalentTo(other.MyCollectionProp) && // See http://stackoverflow.com/a/9658866/141172
this.MyContainedClass.Equals(other.MyContainedClass));
}
public override int GetHashCode()
{
int hashOfMyCollectionProp = 0;
// http://computinglife.wordpress.com/2008/11/20/why-do-hash-functions-use-prime-numbers/
// BUT... is it worth the extra math given that elem.GetHashCode() should be well-distributed?
int bitSpreader = 31;
foreach (var elem in MyCollectionProp)
{
hashOfMyCollectionProp = spreader * elem.GetHashCode();
bitSpreader *= 31;
}
return base.GetHashCode() ^ // ^ is a good combiner IF the combined values are well distributed
MyIntProp.GetHashCode() ^
(MyStringProp == null ? 0 : MyStringProp.GetHashValue()) ^
(MyContainedClass == null ? 0 : MyContainedClass.GetHashValue()) ^
hashOfMyCollectionProp;
}
Мои вопросы
- Является ли шаблон реализации надежным?
- Является ли ^ адекватным, учитывая, что составляющие значения компонентахорошо распределены?Нужно ли умножать на 31-на-N при объединении элементов коллекции, учитывая, что их хэш хорошо распределен?
- Кажется, что этот код можно абстрагировать в код, который использует отражение для определения открытых свойств, создает выражениедерево, которое соответствует решению, закодированному вручную, и выполняет дерево выражений по мере необходимости.Этот подход кажется разумным?Есть ли где-нибудь существующая реализация?