C # Overriding Equals, используя «как» и специализированный метод правильности, гибкости и производительности - PullRequest
3 голосов
/ 20 января 2009

Я задавался вопросом о лучшем способе реализации правильных, гибких и быстрых равных в C #, которые можно использовать практически для любого класса и ситуации . Я понял, что для производительности необходим специализированный метод Equals (принимая объект фактического класса в качестве параметра). Чтобы избежать дублирования кода, общие Equals должны вызывать специализированные Equals. Нулевые проверки должны выполняться только один раз, даже в унаследованных классах.

Я наконец-то придумал этот дизайн:


class MyClass
{
    public Int32 SomeValue1 = 1;
    public Int32 SomeValue2 = 25;

    // Ignoring GetHashCode for simplicity.

    public override bool Equals(object obj)
    {
        return Equals (obj as MyClass);
    }

    public bool Equals(MyClass obj)
    {
        if (obj == null) {
            return false;
        }

        if (!SomeValue1.Equals (obj.SomeValue1)) {
            return false;
        }

        if (!SomeValue2.Equals (obj.SomeValue2)) {
            return false;
        }

        return true;
    }
}

class MyDerivedClass : MyClass
{
    public Int32 YetAnotherValue = 2;

    public override bool Equals(object obj)
    {
        return Equals (obj as MyDerivedClass);
    }

    public bool Equals(MyDerivedClass obj)
    {
        if (!base.Equals (obj)) {
            return false;
        }

        if (!YetAnotherValue.Equals (obj.YetAnotherValue)) {
            return false;
        }

        return true;
    }
}

Важные идеи:

  • Использование оператора as. Таким образом, нам не нужно проверять наличие нулей в общих равных. Неправильные типы классов уменьшаются до нуля и будут отсортированы в специализированных Equals.
  • Нулевая проверка ровно в одной точке, даже для производных классов.
  • Проверка атрибутов один за другим обеспечивает четкую структуру.

Есть ли недостатки в этих концепциях, или я пропустил какие-либо условия?

1 Ответ

5 голосов
/ 20 января 2009

Ваш метод Equals не является рефлексивным, когда задействованы различные типы:

MyDerivedClass mdc = new MyDerivedClass();
MyClass mc = new MyClass();
Object omdc = mdc;
Object omc = mc;

// mc.Equals(mdc) - true
// mdc.Equals(mc) - true by calling the right overload
// omc.Equals(omdc) - true
// omdc.Equals(omc) - false, the "as" in MyDerivedClass will result in null

Обычный способ это использовать:

if (GetType() != other.GetType())
{
    return false;
}

См. Документы в Object.Equals : "x.Equals (y) возвращает то же значение, что и y.Equals (x)." Полагаясь на перегрузку для получения разных результатов, вы можете столкнуться с ужасными проблемами, которые очень трудно отладить.

...