【问题标题】:How to call protected constructor in c#?如何在 C# 中调用受保护的构造函数?
【发布时间】:2011-05-20 22:15:07
【问题描述】:

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

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

【问题讨论】:

    标签: c# inheritance constructor


    【解决方案1】:

    调用无参数受保护/私有构造函数:

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

    【讨论】:

      【解决方案2】:

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

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

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

      foo is Foo 形式的断言通过。

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

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

      【讨论】:

      • “但我劝你不要这样做”为什么不呢?我需要那个来测试。也许这毕竟是有道理的?
      • @Arnis L.:此时,您所做的只是想出一个技巧来通过测试,这与根本不编写测试一样有用。现在是退后一步,看看为什么这个构造函数是protected的好时机,因为它暗示你寻求(并且正在测试)的行为是明确不受支持的(因此,不可测试)。
      • @Arnis:通常如果您需要通过反射绕过可访问性模型,这表明您不应该尝试访问相关成员 - 或者您应该自己增加可访问性。跨度>
      • @David 这更像是创建测试夹具。我不是在测试 Foo 本身。因此 - 我没有兴趣满足 Foo 通常要求的所有需求,也不会放松它们。
      • @Arnis:您可能需要考虑使用protected internal,然后使用InternalsVisibleTo 以允许您的测试程序集访问生产程序集的内部。
      【解决方案3】:

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

      编辑:飞碟说了什么!

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          Serj-Tm 回答充分,但 Activator 也能做到:

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

          【讨论】:

            【解决方案6】:

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

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

            【讨论】:

              【解决方案7】:

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

              【讨论】:

                【解决方案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() { }
                
                    }
                

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

                【讨论】:

                  猜你喜欢
                  • 2012-06-04
                  • 2011-05-30
                  • 2021-10-05
                  • 2014-05-08
                  • 2016-04-07
                  • 1970-01-01
                  • 2014-11-03
                  • 2010-09-17
                  • 1970-01-01
                  相关资源
                  最近更新 更多