代码之家  ›  专栏  ›  技术社区  ›  AndrewJacksonZA

从C中的类外部访问私有构造函数#

  •  22
  • AndrewJacksonZA  · 技术社区  · 14 年前

    如果我用一个私有的默认构造函数和一个有参数的公共构造函数定义一个类,我如何访问私有的构造函数?

    public class Bob
    {
       public String Surname { get; set; }
    
       private Bob()
       { }
    
       public Bob(string surname)
       {
          Surname = surname;
       }
    }
    

    我可以通过类上的静态方法访问私有构造函数,如下所示:

    public static Bob GetBob()
    {
       return new Bob();
    }
    

    我认为我可以通过一个扩展方法访问私有构造函数,因为(根据我的理解)扩展方法被翻译成 似乎是 类上的静态方法,但我不能:

    static class Fred
    {
       public static Bob Bobby(this Bob bob)
       {
          return new Bob();
       }
    }
    

    那么,如何访问私有构造函数呢?

    谢谢你


    编辑:

    我之所以要这样做,是因为我想为我们的一个业务类创建测试,但不允许此类的使用者能够错误地实例化对象。我正在测试它,所以我知道(我希望!)在什么情况下测试会失败。我现在仍然是一个测试n00b,所以我的想法可能是,也可能不是做事情的“错误方式”。

    我已经改变了我的测试策略,以像这个类的使用者那样做事情,即调用公共方法,如果公共方法是可以的,假设私有方法是可以的。我还是喜欢测试私人方法,但是我的老板 把我的脖子压在一个可交付物上:-(

    7 回复  |  直到 6 年前
        1
  •  43
  •   jgauffin    14 年前

    由于某种原因,默认构造函数是私有的。开发人员并不是为了好玩而把它变成私人的。

    但是,如果您仍然想使用默认的构造函数,您可以使用反射来获得它。

    var constructor = typeof(Bob).GetConstructor(BindingFlags.NonPublic|BindingFlags.Instance, null, new Type[0], null);
    var instance = (Bob)constructor.Invoke(null);
    

    编辑

    我看到你对测试的评论了。从不测试受保护的或私有的方法/属性。如果您无法通过公共API测试这些方法/属性,那么您可能做了一些错误的事情。要么删除它们,要么重构类。

    编辑2

    忘记绑定标志。

        2
  •  2
  •   Dr Herbie    14 年前

    有几种方法可以解决这个问题:

    :将构造函数公开。如果您需要从类外部访问它,为什么它是私有的(可能您只想访问私有构造函数进行测试,在这种情况下这是一个有效的问题)。

    :使构造函数受保护,然后通过派生类访问它:

    public class Bob
    {
        public String Surname { get; set; }
    
        protected Bob()
        { }
    
        public Bob(string surname)
        {
            Surname = surname;
        }
    }
    
    public class Fred : Bob
    {
        public Fred()
            : base()
        {
        }
    }
    

    :使用反射(如jgauffin所示)。

        3
  •  2
  •   Cheng Chen    6 年前

    除了@jgauffin的答案外,它还告诉如何通过反射调用私有构造函数:

    是否可以更改私有构造函数的修饰符?

    似乎您正在代码中实现工厂模式。因此,修饰符应该是 internal .

    public class Product
    {
       //others can't create instances directly outside the assembly
       internal Product() { }    
    }
    public class ProductProvider
    {
       //they can only get standardized products by the provider
       //while you have full control to Product class inside ProductProvider
       public static Product CreateProduct()
       {
           Product p = new Product();    
           //standardize the product
           return p;
       }  
    }
    

    扩展方法

    public static MyExt
    {
       public static void DoSomething(this Product p) { }
    }
    

    打电话 p.DoSomething() 实际上等于 MyExt.DoSomething(p) . 它不会将此方法放入类产品中。

        4
  •  0
  •   Frederik Gheysels    14 年前

    您可以通过反射来实例化该类型的实例。

        5
  •  0
  •   Liviu Mandras    14 年前

    Bobby的方法仍然属于另一个类,叫做Fred。这就是为什么您不能访问Bob类的prive构造函数。附加方法不可能实现您正在尝试的操作。即使它们可以附加到另一个类上,它们仍然在该类之外声明,并遵循通常的范围/访问规则。

        6
  •  0
  •   DenLilleMand    8 年前

    如果您使用的是dotnet core,那么您可以在不需要处理任何反射的情况下执行以下操作:

    YourCustomObject player = (YourCustomObject)Activator.CreateInstance(typeof(YourCustomObject),true);
    
        7
  •  -1
  •   Martin Prikryl    10 年前
    public class demo
    {
       private demo()
        {
            Console.WriteLine("This is no parameter private constructor");
        }
        public demo(int a)
        {
            demo d = new demo('c');// u can call both private contstructors from here
            demo dd = new demo();
            Console.WriteLine("This is one parameter public constructor");
        }
        private demo(char a)
        {
            Console.WriteLine("This is one parameter public constructor::" + a);
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            demo obj = new demo(7);
            // demo obj = new demo();  // it will raise error
            Console.ReadLine();
        }
    }