2015-10-27 2 views
7

Упрощенная ситуацияInstance поле подкласса, используя родительский защищенный конструктор

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

Почему это невозможно создать экземпляр А в классе B, используя класс защищенный конструктор?

В моем сознании защищенный конструктор подобен защищенному методу, поэтому его можно запустить в подклассе.

+1

для вызова базового конструктора вы можете 'private B(): base()' – Grundy

+0

можете ли вы предоставить сообщение об ошибке _full_? – Grundy

+1

hm, я получаю еще одну ошибку: _Cannot получить доступ к защищенному члену «A.A()» через квалификатор типа «A»; квалификатор должен быть типа «B» (или получен из него) _ – Grundy

ответ

5

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

Вы не может вызова защищенного конструктор с помощью модификатора new потому что цель в защищенного конструктора является то, что он может быть вызван только из производных классов точки зрения, таким образом, не видны из "за пределами".

Компилятор не делает вывод, что вызов new A() выполняется из экземпляра B. Вот почему синтаксис конструктора доступен, чтобы гарантировать соглашение о том, как вызвать базовые конструкторы.

Тобой можно назватьA конструктор при объявлении конструктора для B:

public B(string foo) : base(foo) 

Это то, что на самом деле это делается от Вашего имени конструктора по умолчанию. Например:

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

даст следующий 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 

Один хака пути (я бы не делать этого), чтобы создать такой экземпляр может быть достигнут с Activator.CreateInstance перегрузкой, который принимает bool флага что указывает конструктор является непубличной:

var b = (B)Activator.CreateInstance(typeof(B), nonPublic: true); 
+0

, но в OP, 'B' класс имеет поле для базового класса и попробуйте запустить его. – Grundy

+0

@ Grundy Точно, он не может этого сделать. Вот что я заявляю в своем ответе :) –

+0

Возможно, я просто пропустил основную часть вашего ответа :-), хотя вы говорите, что просто называете конструктор 'A' базой для' B', а не как поле инициализации – Grundy

3

Вы можете сделать конструктор Aprotected internal:

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

Таким образом, тип или элемент может быть доступен любым кодом в сборке, в котором она объявлена, или в пределах от производного класса в другой сборке.

Посмотрите на эту ссылку для получения более подробной информации: Many Questions: Protected Constructors.

0

Попробуйте изменить код

a = this.Make(); 

Надеется, что это может помочь вам понять код лучше. Per MSDN

A protected member is accessible within its class and by derived class instances.

Так что, когда вы звоните this.Make(), вы обращаетесь к protected constructor в derived class instances. Когда вы вызываете new A() внутри class B, текущий экземпляр this и новый экземпляр, который будет создан, представляют собой два разных экземпляра. Фактически вы получаете доступ к конструктору A за пределами производного класса A или A.

+0

'Make' уже работает, а не работает конструктор прямого вызова – Grundy

+0

@Grundy, я не сказал' Make' не работает. Я хочу, чтобы OP понимал «это» в контексте. – qxg

2

protected члены доступны в производном классе (подклассе) только через ссылку экземпляра типа производного класса (или другого производного класса).

Вот пример с методами вместо конструкторов:

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

Таким образом, в приведенном выше примере, вы можете вызвать M на C внутри C, но вы не можете назвать M на B внутри C.

Ваш пример с конструкторами экземпляров аналогичен. A new выражение объекта похоже на вызов члена экземпляра (конструктор экземпляра) на (новом) объекте типа, записанного после new.

Смежные вопросы