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

时间:2010-12-06 11:09:19

标签: 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());

8 个答案:

答案 0 :(得分:26)

调用无参数的protected / private构造函数:

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

答案 1 :(得分:21)

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

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

但是,您的断言将失败,因为引用的对象类型为foo,而不是FooMock

Foo 形式的断言将传递。

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

你可以在一个完整的信任环境中用反射来调用它,但我敦促你不要这样做。

答案 2 :(得分:3)

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

编辑:Skeet说的是什么!

答案 3 :(得分:1)

您无法调用protected方法 - 尽管您可以调用internal个方法(使用InternalsVisibleTo属性)。您需要以不同的方式公开它。

答案 4 :(得分:1)

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

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

答案 5 :(得分:0)

如果您需要在子类中显式调用基类的构造函数,则必须使用关键字 base

答案 6 :(得分:0)

Serj-Tm回答得很充分,但Activator也可以这样做:

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

答案 7 :(得分:0)

可能会有所帮助:

抽象父类:

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

    }

在main函数中实现:

       public static void Main(string[] args)
        {


            Animal lion = new Simba();
            lion.Name = "Simba";
            lion.talk(); 
            Animal lion1 = new Kiara();
            lion1.Name = "Kiara";
            lion1.talk();
        }