Оператор равенства на подклассе, а также абстрактный класс - PullRequest
0 голосов
/ 12 марта 2019

Допустим, у нас есть следующие простые классы:

abstract class Abc { }

class Bcd : Abc { public int val; }

По умолчанию оператор == в экземплярах Bcd возвращает false в этом примере:

var result_1 = new Bcd() { val = 10 } == new Bcd() { val = 10 };

Итак, следуя указаниям здесь , оператор == можно добавить к Bcd:

class Bcd : Abc
{
    public int val;

    public bool Equals(Bcd obj)
    {
        if (Object.ReferenceEquals(obj, null)) return false;
        if (Object.ReferenceEquals(obj, this)) return true;
        if (obj.GetType() != GetType()) return false;

        return obj.val == val;
    }

    public override bool Equals(object obj) => Equals(obj as Bcd);

    public override int GetHashCode() => val.GetHashCode();

    public static bool operator ==(Bcd a, Bcd b)
    {
        if (Object.ReferenceEquals(a, null))
        {
            if (Object.ReferenceEquals(b, null)) return true;

            return false;
        }

        return a.Equals(b);
    }

    public static bool operator !=(Bcd a, Bcd b) => !(a == b);
}

А теперь выражение оценивается как истинное:

var result_1 = new Bcd() { val = 10 } == new Bcd() { val = 10 };

Однако я могу захотеть хранить экземпляры Bcd (и, возможно, другие экземпляры других подклассов Abc) в переменных, типизированных как Abc:

Abc a = new Bcd() { val = 10 };
Abc b = new Bcd() { val = 10 };

Теперь это, конечно, вернет false:

var result_2 = a == b;

Один из способов получить желаемое поведение - это также добавить методы равенства в Abc (даже если это абстрактный класс):

abstract class Abc
{
    public bool Equals(Abc obj)
    {
        if (obj is Bcd && this is Bcd) return (obj as Bcd) == (this as Bcd);

        return false;
    }

    public static bool operator ==(Abc a, Abc b)
    {
        if (Object.ReferenceEquals(a, null))
        {
            if (Object.ReferenceEquals(b, null)) return true;

            return false;
        }

        return a.Equals(b);
    }

    public static bool operator !=(Abc a, Abc b) => !(a == b);
}

Теперь выражение возвращает true:

Abc a = new Bcd() { val = 10 };
Abc b = new Bcd() { val = 10 };

var result_2 = a == b;

Мой вопрос таков: является ли рекомендуемый подход добавлением оператора равенства (и метода Equals, оператора != и т. Д.) К абстрактному родительскому классу Abc вышеуказанным способом? Чувствуется небольшая пробка. Более того, если в будущем Abc будет снова разделено на подклассы, оператор Equals в Abc необходимо обновить; это также кажется немного странным.

Есть ли рекомендуемые руководства для этого шаблона?

...