30

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

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,所以我的想法可能是也可能不是做事的“错误方式”。

我已经改变了我的测试策略,只做这个类的消费者会做的事情,即调用公共方法,如果公共方法没问题,假设私有方法没问题。我仍然更愿意测试私有方法,但我的老板对可交付成果感到不满:-(

4

8 回答 8

55

新答案(九年后)

现在有几个Activator.CreateInstance的重载允许您使用非公共构造函数:

Activator.CreateInstance(typeof(YourClass), true);

true= 使用非公共构造函数。

.

旧答案

默认构造函数是私有的是有原因的。开发人员不会为了好玩而将其设为私有。

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

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

编辑

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

编辑 2

忘记绑定标志。

于 2010-11-12T08:30:16.850 回答
2

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

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

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

public class Bob
{
    public String Surname { get; set; }

    protected Bob()
    { }

    public Bob(string surname)
    {
        Surname = surname;
    }
}

public class Fred : Bob
{
    public Fred()
        : base()
    {
    }
}

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

于 2010-11-12T08:33:36.950 回答
2

除了@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)。它不是将此方法放入类 Product 中。

于 2010-11-12T09:22:05.720 回答
1

如果您使用的是 dotnet core,您可以执行以下操作,甚至无需摆弄任何反射:

YourCustomObject player = (YourCustomObject)Activator.CreateInstance(typeof(YourCustomObject),true);

Activator 就在 System 命名空间中。

于 2017-01-22T17:16:21.153 回答
0

如果一个类只有私有构造函数而没有公共构造函数,则只能从该类中的嵌套类访问它。值得考虑的是不能派生具有私有默认构造函数的类这一事实。因此,只有当类中的实例旨在仅在此类内的嵌套类中创建时,才将构造函数或构造函数声明为私有(在没有公共讲师的类中)。没有其他有效的地方可以实例化这个类。

于 2020-02-15T12:35:25.620 回答
-1

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

于 2010-11-12T08:30:24.430 回答
-1
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();
    }
}
于 2014-04-04T06:57:41.060 回答
-2

Bobby 方法仍在另一个类中,称为 Fred。这就是为什么您不能访问 Bob 类的私有构造函数的原因。附加方法无法完成您尝试做的事情。即使它们可以附加到另一个类上,它们仍然在该类之外声明并遵循通常的范围/访问规则。

于 2010-11-12T08:29:35.007 回答