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

发布于 2025-01-10 18:08:07 字数 823 浏览 0 评论 0原文

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

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

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

谢谢


编辑:

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

我已经更改了我的测试策略,以此类的使用者的方式执行操作,即调用公共方法,如果公共方法正常,则假设私有方法正常。我仍然更愿意测试私有方法,但我的老板正在对我的交付成果进行严格要求:-(

If I define a class with a private default constructor and a public constructor that has parameters, how can I access the private constructor?

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

   private Bob()
   { }

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

I can access the private constructor via a static method on the class like this:

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

I thought that I could access the private constructor via an extension method, since (according to my understanding) extension methods are translated so that they appear to be static methods on the class, but I can't:

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

So, how can I access the private constructor?

Thank you


EDIT:

The reason that I wanted to do this was that I wanted to create tests for one of our business classes, but not allow a consumer of this class to be able to instantiate an object incorrectly. I'm testing it, so I know (I hope!) under what circumstances the tests will fail. I'm still a testing n00b right now so my idea may or may not have been the "wrong way" of doing things.

I've changed my testing strategy to just do things the way the a consumer of this class would, i.e. calling the public methods and if the public methods are OK, assuming that the private methods are OK. I would still prefer to test the private methods, but my boss is breathing down my neck on a deliverable :-(

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

淡看悲欢离合 2025-01-17 18:08:07

新答案(九年后)

现在有几个重载 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

忘记了绑定标志。

New answer (nine years later)

There is now several overloads for Activator.CreateInstance that allow you to use non public constructors:

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

true = use non public constructors.

.

Old answer

Default constructors are private for a reason. The developer doesn't make it private for fun.

But if you still want to use the default constructor you get it by using reflection.

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

Edit

I saw your comment about testing. Never test protected or private methods / properties. You have probably done something wrong if you can't manage to test those methods/properties through the public API. Either remove them or refactor the class.

Edit 2

Forgot a binding flag.

马蹄踏│碎落叶 2025-01-17 18:08:07

有多种方法可以解决此问题:

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

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

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

    protected Bob()
    { }

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

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

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

There are several ways around this issue:

One: Make the constructor public. If you need to access it from outside the class why is it private (it might be that you only want to access the private constructor for testing, in which case this is a valid issue).

Two: Make the constructor protected, then access it through a derived class:

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

    protected Bob()
    { }

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

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

Three: Use reflection (as shown by jgauffin).

冷清清 2025-01-17 18:08:07

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

Is it possible to change the modifiers of the private constructor?

看来您正在代码中实现工厂模式。因此修饰符应该是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 类中。

In additional to @jgauffin's answer which tells how to call private constructors via reflection:

Is it possible to change the modifiers of the private constructor?

It seems that you are implementing Factory Pattern in your code. Thus the modifier is supposed to be 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;
   }  
}

Extension methods

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

Calling p.DoSomething() actually equals to MyExt.DoSomething(p). It's not putting this method into class Product.

数理化全能战士 2025-01-17 18:08:07

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

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

Activator 位于 System 命名空间中。

If you're using dotnet core you can do the following without even having to fiddle with any reflection:

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

Activator is just in the System namespace.

若言繁花未落 2025-01-17 18:08:07

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

if a class has only private and no public constructors, it can only be only accessible from nested classes within this class. what is worthy taking into consideration is the fact that classes with private default constructor cannot be derived.
so it only makes sense to declare constructor or constructors as private (in a class which has no public instructors) when the instances from the class are aimed to be created only within nested classes inside this class. there is no other valid places for instancing this class.

意犹 2025-01-17 18:08:07

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

You can instantiate instances of that type via reflection.

梦旅人picnic 2025-01-17 18:08:07
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();
    }
}
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();
    }
}
时光是把杀猪刀 2025-01-17 18:08:07

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

The method Bobby is still in a different class, called Fred. That is why you can't access the prive constructor of the Bob class. What you are trying to do is not possible with attached methods. Even if they can be attached on another class they are still declared outside that class and follow the usual scope/access rules.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文