У меня есть структура классов, подобная этой, где абстрактный класс A содержит интерфейс IB и конкретный класс C в двух переменных. Какие классы назначаются этой интерфейсной переменной, зависит от фактического подкласса A1, A2, который наследует абстрактный класс, и нуждается в том классе C, который создается в конструкторе родительского класса. Итак, первое, что я придумал, было следующее:

abstract class A
{
    protected readonly IB _b;
    protected readonly C _c;

    protected A()
    {
        _c = new C();
    }
}

class B1 : IB
{
   public B1(C c) {}
}

class B2 : IB
{
   public B2(C c) {}
}

class A1 : A
{
    public A1() : base()
    {
        _b = new B1(_c);
    }
}

class A2 : A
{
    public A2() : base()
    {
        _b = new B2(_c);
    }
}

Присвоение _b = новый B1 (_c); не работает, потому что он защищен. Я также не могу передать класс Bx базовому конструктору, потому что мне нужно, чтобы он был выполнен, прежде чем я смогу создать экземпляр Bx. Как еще я могу достичь желаемого результата?

2
downforme 15 Сен 2021 в 15:25

2 ответа

Лучший ответ

_b = ... не работает, потому что поля, доступные только для чтения, могут быть инициализированы только в конструкторе класса, который его объявляет, а не в подклассе. Это не потому, что _b защищен. В документации говорится:

В объявлении поля readonly указывает, что присвоение полю может происходить только как часть объявления или в конструкторе в том же классе .

Один из способов обойти это - заставить суперкласс взять Func<C, B1> и инициализировать там _b.

protected A(Func<C, IB> bCreator)
{
    _c = new C();
    _b = bCreator(_c);
}

Тогда:

class A1 : A
{
    public A1() : base(c => new B1(c))
    {
        
    }
}

class A2 : A
{
    public A2() : base(c => new B2(c))
    {
        
    }
}
2
Sweeper 15 Сен 2021 в 12:34

Поле readonly может быть создано только в том же классе , но не в подклассе. Таким образом, конструктор A должен установить _b.

Однако вы можете передать знания о том, как установить _b из подкласса в абстрактный базовый класс, передав лямбда-выражение:

Конструктор для A:

protected A(Func<C, IB> bFactory)
{
    _c = new C();
    _b = bFactory(_c);
}

Конструктор для A1:

public A1() : base(c => new B1(c)) { }
2
Heinzi 15 Сен 2021 в 12:32