Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instance subclass field using parent protected constructor

Simplified situation

public class A {
    protected A() { }
    protected A Make() { return new A(); }
}

public class B : A {
    A a = new A(); //inaccessible due to protection level
    B b = new B();

    private B()
    {
        A c = new A();//inaccessible due to protection level
        a = new A(); //inaccessible due to protection level
        a = Make();
    }
}

Why it's impossible to create instance of A in class B using class A protected constructor?

In my mind protected constructor is like protected method so it should be possible to run it in subclass.

like image 400
WloHu Avatar asked Oct 27 '15 09:10

WloHu


3 Answers

Why it's impossible to create instance of A in class B using class A protected constructor?

You can't call a protected constructor using the new modifier because the purpose of a protected constructor is that it can only be called from a derived classes point of view, thus not visible from the "outside".

The compiler doesn't infer the call to new A() is being done from an instance of B. That is why the constructor syntax is available, to guarantee a convention of how to call base constructors.

You can call A constructor when declaring a constructor for B :

public B(string foo) : base(foo)

This is what actually is being done on your behalf for a default constructor. For example:

public class A {}
public class B : A
{
    public B() {}
}

Will yield the following IL:

// Methods
.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Method begins at RVA 0x205a
    // Code size 7 (0x7)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void A::.ctor() <--- This.
    IL_0006: ret
} // end of method B::.ctor

One hackish way (I would avoid doing that) is to create such an instance can be achieved with Activator.CreateInstance overload which accepts a bool flag indicating the constructor is non-public:

var b = (B)Activator.CreateInstance(typeof(B), nonPublic: true);
like image 115
Yuval Itzchakov Avatar answered Sep 21 '22 18:09

Yuval Itzchakov


You can make constructor A protected internal:

public class A
{
    protected internal A() { }
    protected A Make() { return new A(); }
}

So the type or member can be accessed by any code in the assembly in which it is declared, or from within a derived class in another assembly.

Have a look at this link for more details: Many Questions: Protected Constructors.

like image 29
Salah Akbari Avatar answered Sep 23 '22 18:09

Salah Akbari


protected members are accessible in a derived class (subclass) only through an instance reference of the type of the derived class (or a further derived class).

Here is an example with methods instead of constructors:

class B
{
  protected void M() { }
}
class C : B
{
  void X()
  {
    M(); // OK, same as this.M()
  }
  void Y(C otherC)
  {
    otherC.M(); // OK
  }
  void Z(B otherB)
  {
    otherB.M(); // compile-time error CS1540
  }
}

So in the above example, you can call M on a C inside C, but you cannot call M on a B inside C.

Your example with instance constructors is analogous. A new object expression is like calling an instance member (the instance constructor) on a (new) object of the type written after new.

like image 28
Jeppe Stig Nielsen Avatar answered Sep 20 '22 18:09

Jeppe Stig Nielsen