Как выполнить метод в базовом классе после полной инициализации дочернего элемента?

#c# #.net #constructor #abstract-class

#c# #.net #конструктор #абстрактный класс

Вопрос:

Я реализовал следующую структуру:

 public abstract class A
{
    protected A()
    {
        Test();
    }

    private void Test()
    {
        Console.WriteLine("2");
    }
}

public class B : A
{
    public B() : base()
    {
        Console.WriteLine("1");
    }
}
  

Когда я создаю экземпляр класса B , метод Test() выполняется перед вызовом конструктора в классе B . В моем случае этот метод должен выполняться после полной инициализации дочернего элемента. Возможным способом заставить его работать было бы сделать Test() доступным из B и вызвать его в конце его конструктора. Это сработало бы, но если кто-то создаст другой подкласс A , есть вероятность, что он забудет вызвать метод. Мой вопрос заключается в том, существует ли более общее решение в базовом классе, чтобы убедиться, что метод выполняется после полной инициализации дочернего элемента.

Комментарии:

1. Это обычный запрос. Для этого в . Среда выполнения NET или язык C #.

Ответ №1:

Ответ — нет.

В него ничего не встроено .NET или C #, которые могут убедиться, что методы вызываются после выполнения всех конструкторов-потомков.

Другим подходом была бы некоторая форма фабричного шаблона, где ваш класс в основном просто предоставил бы вам другой экземпляр, который был правильно настроен, и все необходимые методы вызывались.

Ответ №2:

Это невозможно сделать, потому что инициализатор конструктора не работает таким образом. Скорее вы можете выбрать передачу некоторого параметра в базовый конструктор, параметры, которые могут быть специфичны для вашего дочернего класса, например

 public abstract class A
{
    protected A(string data)
    {
        Test(data);
    }

    private void Test(string data)
    {
        Console.WriteLine(data);
    }
}

public class B : A
{
    public B() : base("1")
    {
        //some other initialization logic here
    }
}
  

Комментарии:

1. Это может быть делегат, который вызывается раньше Test() и содержит унаследованную инициализацию, специфичную для класса. Тогда унаследованный конструктор класса можно оставить пустым. Но некоторые функции (например, установка значения в авто-свойства только для геттера) не будут работать.

Ответ №3:

Вы не можете напрямую «вставить» вызов метода перед вызовом конструктора базового класса, потому что он вызывает метод для неинициализированного объекта. Но вы можете использовать шаблон метода шаблона:

 abstract class A {

    protected A () {
        BeforeTest ();
        Test ();
    }

    protected abstract void BeforeTest ();

    private void Test () {
        Console.WriteLine ("2");
    }

}


class B : A {

    protected override void BeforeTest () {
        Console.WriteLine ("1");
    }

}


internal class Program {

    public static void Main (string [] args) {
        new B ();
    }

}
  

Кроме того, вы можете сделать Test метод виртуальным:

 abstract class A {

    protected A () {
        Test ();
    }

    protected virtual void Test () {
        Console.WriteLine ("2");
    }

}


class B : A {

    protected override void Test () {
        Console.WriteLine ("1");
        base.Test ();
    }

}


internal class Program {

    public static void Main (string [] args) {
        new B ();
    }

}
  

Оба примера выдают один и тот же результат:

 1
2