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

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

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

Ответ 1

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

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

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

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

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

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

Ответ 2

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

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

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

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

  class Foo
  {
     private Foo(double x){...}
  }

Ответ 3

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

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

Ответ 4

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

Ответ 5

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

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

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

private static readonly Lazy<Func<string, T>> CreateInstance = new Lazy<Func<string, T>>(CreateInstanceFunc);

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

CreateInstance.Value("Hello")

Ответ 6

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

Ответ 7

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

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

Ответ 8

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

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

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