如何在c#中调用受保护的构造函数?

如何在c#中调用受保护的构造函数?,c#,inheritance,constructor,C#,Inheritance,Constructor,如何调用受保护的构造函数 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()); 基本上,只能从子类调用它。您的FooMock类将已经在调用受保护的构造函数,因为它等效于: publi

如何调用受保护的构造函数

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

基本上,只能从子类调用它。您的
FooMock
类将已经在调用受保护的构造函数,因为它等效于:

public class FooMock : Foo
{
    public FooMock() : base() // Call the protected base constructor
    {
    }
}
但是,您的断言将失败,因为引用的对象类型是
foo
FooMock
,而不是
foo

将通过
foo is foo
形式的断言

您不能通过直接调用受保护的构造函数来构造仅
Foo
的实例。保护它而不是公共的目的是确保它只被子类调用(或者在
Foo
本身的文本中)


您可以在完全信任上下文中使用反射调用它,但我建议您不要这样做。

导致调用受保护构造函数的唯一方法是从类派生,并将派生类委托给它,或者让静态方法创建它或其他内部方法


编辑:双向飞碟说了什么

您不能调用
受保护的
方法-尽管您可以调用
内部
方法(使用
InternalsVisibleTo
属性)。您需要以不同的方式公开它。

如果您需要在子类中显式调用基类的构造函数,则必须使用关键字调用无参数受保护/私有构造函数:

Foo foo = (Foo)Activator.CreateInstance(typeof(Foo), true);
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() { }
    }
使用参数调用非公共构造函数:

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

Serj Tm回答得很好,但Activator也能做到:

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

如果要避免重复反射成本,可以使用表达式。 下面是一个使用字符串值调用私有构造函数的示例

    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();
    }
这可能有助于:

抽象父类:

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

        }


    }
使用受保护的构造函数初始化:

Foo foo = (Foo)Activator.CreateInstance(typeof(Foo), true);
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() { }

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

    }
Simba类派生自Lion类:

 public class Kiara : Lion
    {

        public Kiara(string name) : base(name)
        {

        }

        public override void talk()
        {

            Console.WriteLine("HRRRR I'm a Kiara");

        }

        public Kiara() { }

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

“但我劝你不要这样做”为什么不呢?我需要那个做测试。也许这终究是有道理的?@Arnis L:在这一点上,你所做的仅仅是想出一个黑客来通过测试,这和根本不写测试一样有用。现在是退后一步,看看为什么此构造函数受保护的好时机,因为这意味着您寻求(和正在测试)的行为明显不受支持(因此不可测试)。@Arnis:通常如果您需要通过反射绕过可访问性模型,这表明您不应该试图访问有问题的成员,或者您应该自己增加可访问性。@David这更像是创建测试夹具。我不是在测试Foo本身。因此,我不想满足FoO通常要求的所有需求,也不必松开它们。@ Arnis:您可能想考虑使用<代码>受保护的内部< /代码>,然后使用<代码>内部VISILBUTO >允许测试程序集访问生产程序集的内部组件。