Как вызвать защищенный конструктор в С#?

Как вызвать защищенный конструктор?

public class Foo{
 public Foo(a lot of arguments){}
 protected Foo(){}
}
var foo=???

Это, очевидно, не проходит тест:

public class FooMock:Foo{}
var foo=new FooMock();
Assert(typeof(Foo), foo.GetType());
8 ответов

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

public class FooMock : Foo
{
 public FooMock() : base() // Call the protected base constructor
 {
 }
}

Однако ваше утверждение не будет выполнено, потому что тип объекта, называемый foo, равен FooMock, а не foo.

Будет выполнено утверждение формы foo is Foo.

Вы не можете создать экземпляр только foo, вызвав защищенный конструктор напрямую. Точка его защиты, а не публичная, заключается в том, чтобы она вызывалась только подклассами (или внутри самого текста foo).

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


Вызывать бесцельный защищенный/закрытый конструктор:

Foo foo = (Foo)Activator.CreateInstance(typeof(Foo), true);

Вызов непубличного конструктора с параметрами:

var foo = (Foo)typeof(Foo)
 .GetConstructor(
 BindingFlags.NonPublic | BindingFlags.CreateInstance | BindingFlags.Instance, 
 null, 
 new[] { typeof(******) }, 
 null
 )
 .Invoke(new object[] { 1.0 });
 class Foo
 {
 private Foo(****** x){...}
 }


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

EDIT: Что сказал Скит!


Если вы хотите избежать многократного отражения, вы можете использовать выражения. Ниже приведен пример вызова частного конструктора со строковым значением.

private static Func<string, t=""> CreateInstanceFunc()
 {
 var flags = BindingFlags.NonPublic | BindingFlags.Instance;
 var ctor = typeof(T).GetConstructors(flags).Single(
 ctors =>
 {
 var parameters = ctors.GetParameters();
 return parameters.Length == 1 && parameters[0].ParameterType == typeof(string);
 });
 var value = Expression.Parameter(typeof(string), "value");
 var body = Expression.New(ctor, value);
 var lambda = Expression.Lambda<func<string, t="">>(body, value);
 return lambda.Compile();
 }
</func<string,></string,>

Сохраните стоимость компиляции функции несколько раз, сохранив ее в статическом поле.

private static readonly Lazy<func<string, t="">> CreateInstance = new Lazy<func<string, t="">>(CreateInstanceFunc);
</func<string,></func<string,>

Теперь вы можете создать объект с помощью

CreateInstance.Value("Hello")


Вы не можете вызвать метод protected - хотя вы можете вызвать internal one (используя атрибут InternalsVisibleTo). Вам нужно разоблачить его по-другому.


Если вам нужно явно вызвать конструктор вашего базового класса в вашем подклассе, вы должны использовать ключевое слово base


Возможно, это поможет:

абстрактный родительский класс:

public abstract class Animal
 {
 private string name;
 public Animal(string name)
 {
 this.Name = name;
 }
 public Animal() { }
 public string Name
 {
 get { return this.name; }
 set { this.name = value; }
 }
 public virtual void talk()
 {
 Console.WriteLine("Hi,I am an animal");
 }
 }

класс с защищенным конструктором:

public class Lion : Animal
 {
 private string yahoo;
 protected Lion(string name) : base(name)
 {
 this.Yahoo = "Yahoo!!!";
 }
 public string Yahoo
 {
 get
 {
 return yahoo;
 }
 set
 {
 yahoo = value;
 }
 }
 public Lion() { }
 }

класс Kiara, полученный из класса Lion:

public class Kiara : Lion
 {
 public Kiara(string name) : base(name)
 {
 }
 public override void talk()
 {
 Console.WriteLine("HRRRR I'm a Kiara");
 }
 public Kiara() { }
 }

класс Simba, полученный из класса Lion:

public class Simba : Lion
 {
 public Simba(string name) : base(name)
 {
 }
 public override void talk()
 {
 Console.WriteLine("HRRRR I'm a {0} and this is my daughter:{1} {2}", 
 new Simba("Simba").Name, 
 new Kiara("Kiara").Name, 
 new Simba("Simba").Yahoo);
 }
 public Simba() { }
 }

реализация в основной функции:

public static void Main(string[] args)
 {
 Animal lion = new Simba();
 lion.Name = "Simba";
 lion.talk(); 
 Animal lion1 = new Kiara();
 lion1.Name = "Kiara";
 lion1.talk();
 }


Serj-Tm ответил адекватно, но Activator тоже может это сделать:

var foo = (Foo) Activator.CreateInstance(typeof(Foo), 
 BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, 
 null, 
 new object[] { 2.0 }, 
 CultureInfo.InvariantCulture);

licensed under cc by-sa 3.0 with attribution.