Вызов переопределения виртуальных методов из родительского класса

Предположим, вы пишете исходный класс С# Object, и вам нужны следующие функции:

  • object1 == object2 будет сравнивать ссылки, если этот оператор не переопределен.
  • object1 != object2 всегда будет возвращать обратный объекту ACTUAL object1 == object2

Так, например, если у меня есть класс Bunny (полученный из Object), который использует длины ушей в качестве метода equals, тогда метод notequals (унаследованный от Object) должен возвращать true, если у кроликов есть разные длины ушей.

Проблема, которую я вижу, заключается в том, что если я напишу свой класс Object примерно так:

public partial class Object {
    public virtual bool Equals(Object o2) {
       return (this === o2);
    }

    public bool NotEquals(Object o2) {
       return !this.Equals(o2);
    }
}

то похоже, что это определение привяжет NotEquals к Object Equals, а не к фактическому производному классу.

Есть ли способ, которым это может работать без изменения самого С#? Мне все равно, что это возможно на С#, но мне все равно, есть ли какой-то принцип ООП, который говорит мне, что я не должен ожидать, что это будет работать.

Кроме того, я не уверен, является ли это основополагающим для этого вопроса, но идея заключается в том, чтобы NotEquals был виртуальным, так что он тоже может быть переопределен производными классами, которые хотят, чтобы их o1 != o2 отличались друг от друга от !(o1 == o2). Этот вопрос вдохновлен этим недавним обсуждением.

Ответ 1

Код, который вы предоставили, вызовет производный метод Equals. Equals является виртуальным, и это означает, что при его вызове будет использоваться "наиболее производная" реализация.

Ответ 2

NotEquals не будут привязываться к методу класса класса Object, он будет использовать наиболее производный метод. Вы могли бы легко проверить это. И также легко сделать notEquals виртуальным, поэтому вы можете переопределить это с помощью пользовательской логики.

Использование этих классов (игнорируйте условные обозначения именования):

class parent
{
    public virtual bool equals(parent p)
    {
        Console.WriteLine("parent equals");
        return false;
    }

    public virtual bool notEquals(parent p)
    {
        return !this.equals(p);
    }
}

class child : parent
{
    public override bool equals(parent p)
    {
        Console.WriteLine("child equals");
        return true;
    }
}

Затем выполните следующее:

parent p = new parent();
p.notEquals(null);

child c = new child();
c.notEquals(null);

Результаты этого вывода:

parent equals
child equals

Ответ 3

Возможно, я не понимаю вопроса, но метод NotEquals, объявленный в Object в вашем примере, будет использовать метод Equals, определенный в производном классе (если он объявлен с модификатором переопределения в производном классе), а не на Object.

Возьмем этот простой пример, демонстрирующий это поведение:

void Main()
{
    BaseObject do1 = new DerivedObject();
    BaseObject do2 = new DerivedObject();
    do1.NotEquals(do2);
}


public class DerivedObject : BaseObject
{
    public override bool Equals(BaseObject o2)
    {
        Console.WriteLine("OtherObject.Equals called.");
        return (this == o2);
    }
}

public partial class BaseObject {
    public virtual bool Equals(BaseObject o2) {
       return (this == o2);
    }

    public bool NotEquals(BaseObject  o2) {
       return !this.Equals(o2);
    }
}

Если вы выполните этот пример, вы увидите, что выполняется оператор Console.WriteLine(уберите модификатор переопределения в DerivedObject, а затем Console.WriteLine не будет выполнен).

Вы также можете просмотреть документацию, в которой говорится: "Вызывается переопределяющий член в самом производном классе, который может быть исходным членом, если никакой производный класс не переопределил член.".

Ответ 4

Это не совсем понятно, что вы пытаетесь спросить, потому что вы не можете изменить определение Object поэтому упражнение несколько спорно, но делать вид, что вы можете и на самом деле изменения Object, <класс T22 > на самом деле ссылаются на реализацию производного класса, поскольку Equals является виртуальным.

В частности, я не уверен, что вы подразумеваете под "this" в своем предложении:

"Есть ли способ, которым этот может работать без изменения самого С#?"