Упрощение переопределения Equals(), GetHashCode() в C# для лучшей ремонтопригодности

Я обнаружил, что часто переопределяю 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;
}

Мои вопросы

  1. Надежна ли схема реализации?
  2. Является ли ^ адекватным, учитывая, что значения компонентов хорошо распределены? Нужно ли умножать на 31-к-N при объединении элементов коллекции, учитывая, что их хэш хорошо распределен?
  3. Кажется, что этот код может быть абстрагирован в код, который использует отражение для определения общедоступных свойств, строит дерево выражений, соответствующее решению, написанному вручную, и выполняет дерево выражений по мере необходимости. Такой подход кажется разумным? Есть ли где-нибудь существующая реализация?
9
задан Eric J. 14 March 2012 в 07:29
поделиться