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

Рейтинг: 0Ответов: 2Опубликовано: 18.08.2023

Имеются два класса (родительский дочерний соответственно):

class Unit
{
    protected string UnitChar = ".";

    public string Char
    {
        get => UnitChar;
    }

    public void Print() => Console.WriteLine(Char);
}


class Pawn : Unit
{
    protected new string UnitChar = "P";
}

В наследуемом классе я переопределяю поле UnitChar, присваивая ему строку "P". По моей задумке, метод и свойство, которые наследует Pawn, при вызове из его экземпляра должны использовать его поля и свойства, которые опираются на переопределенное поле. Иными словами, наследуемый метод Print в классе Pawn должен использовать свойство Char, которое, в свою очередь возвращает переопределенный UnitChar.

Однако следующий код:

Unit U = new();
Pawn P = new();
U.Print();
P.Print();
Console.WriteLine($"{U.Char} {P.Char}");

Выводит:

.
.
. .

Хотя ожидается:

.
P
. P

Ответы

▲ 4Принят

Правильнее (в соотвествии с задумкой автора) было бы сделать так:

class Unit {
    protected string UnitChar = ".";
    public string Char { get => UnitChar; }
    public void Print() => Console.WriteLine(Char);
}
class Pawn : Unit {
    public Pawn() :  base() { UnitChar = "P"; }
}

Объяснение в другом ответе. Я бы уточнил, что ключевое слово new "прячет" наследуемое поле и создаёт его новое определени (хотя оно и имеет такое же имя), которое будет использоваться не раньше (в иерархии наследования), чем в этом классе.

▲ 4
class Unit
{
    public virtual string Char => ".";

    public void Print() => Console.WriteLine(Char);
}


class Pawn : Unit
{
    public override string Char => "P";
}

В наследуемом классе я переопределяю поле UnitChar,

Нет. Переопределение происходит только при наличии ключевого слова override. Тогда в методе Print при доступе к свойству Char рантайм будет вызывать его как виртуальный метод и проверять таблицу с типами, чтобы определить какой именно нужно вызвать метод, оригинальный или из наследника.

А ключевого слова new просто "прячет" оригинальный метод и предоставляет новую реализацию (хотя она и имеет такое же имя), которая будет вызываться только тогда, когда на этапе компиляции компилятор определил, что идет именно доступ к этой "версии" метода.

Например, если в вашей версии кода выполнить new Pawn().UnitChar (предположим что оно public), то оно, как и ожидалось, вернет P вместо ..