Как вызвать защищенный конструктор в C #? - PullRequest
13 голосов
/ 06 декабря 2010

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

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 ]

26 голосов
/ 17 марта 2012

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

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){...}
  }
21 голосов
/ 06 декабря 2010

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

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

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

Утверждение вида foo is Foo будет проходить, хотя.

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

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

3 голосов
/ 06 декабря 2010

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

1 голос
/ 24 марта 2017

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

    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")
1 голос
/ 06 декабря 2010

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

0 голосов
/ 29 марта 2017

это может помочь:

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

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

    }

Класс Симба, полученный из класса 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();
        }
0 голосов
/ 28 сентября 2016

Серж-Тм ответил адекватно, но Активатор тоже может это сделать:

var foo = (Foo) Activator.CreateInstance(typeof(Foo), 
               BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, 
               null, 
               new object[] { 2.0 }, 
               CultureInfo.InvariantCulture);
0 голосов
/ 06 декабря 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...