Какой вывод будет у виртуального метода, вызываемого из конструктора абстрактного класса

При создании B возникнет NullReferenceException: конструктор A вызывает B.Foo до выполнения тела конструктора B, где создаётся builder. Строка в консоль не выводится.

Короткий ответ

Что ответить на собеседовании

При создании B возникнет NullReferenceException: конструктор A вызывает B.Foo до выполнения тела конструктора B, где создаётся builder. Строка в консоль не выводится.

Подробный разбор

Ответ с пояснениями

Условие

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

B obj = new B{};

abstract class A
{
    protected A()
    {
        this.Foo();
    }
    protected abstract void Foo();
}

class B : A
{
    private StringBuilder builder;

    public B()
    {
        builder = new StringBuilder();
        builder.Append("hello");
    }

    protected override void Foo()
    {
        builder.Append(" world ");
        Console.WriteLine(builder);
    }
}

Ответ

При создании B возникнет NullReferenceException: конструктор A вызывает B.Foo до выполнения тела конструктора B, где создаётся builder. Строка в консоль не выводится.

Виртуальная диспетчеризация действует и во время построения объекта. Поле builder пока равно null, поэтому исключение возникает на builder.Append, ещё до Console.WriteLine.

Предполагается наличие using System.Text. Главный способ исправления — не вызывать переопределяемые методы из конструктора базы; выполнение, зависящее от готового состояния, переносится после конструирования. Перенос инициализации поля может исправить этот пример, но не устраняет общий риск такого дизайна.

ИИ-помощник для собеседований

Хочешь уверенно проходить собеседования?

Попробуй ИИ-помощник для собеседований: слышит вас и собеседника, анализирует экран, подсказывает ответы в реальном времени, работает без VPN и не попадает в захват экрана.

Подробнее