downforme
downforme

Reputation: 413

abstract class with readonly member

I have a class structure like this where an abstract class A holds an interface IB and a concrete class C in two variables. Which classes get assigned to that interface variable depends on the actual subclass A1, A2 that inherits the abstract class, and need that class C that gets instantiated in the parent class constructor. So what I came up first was this:

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);
    }
}

The assignment _b = new B1(_c); doesn´t work because its protected. I also can´t pass the class Bx down to the base constructor, because I need that to be executed before I can instantiate Bx. How else can I achieve my desired outcome?

Upvotes: 3

Views: 597

Answers (2)

Sweeper
Sweeper

Reputation: 271820

_b = ... doesn't work because readonly fields can only be initialised in the constructor of the class that declares it, not in a subclass. It's not because _b is protected. The documentation says:

In a field declaration, readonly indicates that assignment to the field can only occur as part of the declaration or in a constructor in the same class.

One way to work around this is to have the superclass take in a Func<C, B1>, and initialise _b there.

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

then:

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

class A2 : A
{
    public A2() : base(c => new B2(c))
    {
        
    }
}

Upvotes: 2

Heinzi
Heinzi

Reputation: 172290

A readonly field can only be instantiated in the same class, not in a subclass. Thus, A's constructor needs to set _b.

However, you can pass the knowledge of how to set _b from the subclass to the abstract base class by passing a lambda expression:

Constructor for A:

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

Constructor for A1:

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

Upvotes: 2

Related Questions