为什么我们需要一个私有的构造函数?


70

如果类具有私有构造函数,则无法实例化。因此,如果我不希望实例化我的课程而仍然使用它,则可以将其设为静态。

私有构造函数有什么用?

另外,它在单例类中使用,但除此之外,还有其他用途吗?

(注意:我排除上述单例的原因是,我不明白为什么在有静态类可用的情况下我们根本不需要单例。您可能无法回答这个问题。)

Answers:


72

使用工厂模式(换句话说,用于获取类实例而不是显式实例化的静态函数)时,私有构造函数可能很有用。

public class MyClass
{ 
    private static Dictionary<object, MyClass> cache = 
        new Dictionary<object, MyClass>();

    private MyClass() { }

    public static MyClass GetInstance(object data)
    {
        MyClass output;

        if(!cache.TryGetValue(data, out output)) 
            cache.Add(data, output = new MyClass());

        return output;           
    }
}

伪装嵌套儿童

从外部类继承的任何嵌套类都可以访问私有构造函数。

例如,你可以使用它来创建一个抽象类,可以继承,但没有其他人(的internal构造也将在这里工作,限制继承到一个单一的组件,但private构造强制所有的实现是嵌套类。)

public abstract class BaseClass
{
    private BaseClass() { }

    public class SubClass1 : BaseClass
    {
        public SubClass1() : base() { }
    }

    public class SubClass2 : BaseClass
    {
        public SubClass2() : base() { }
    }
}

基础建设者

它们还可以用于创建从不同的,更易于访问的构造函数调用的“基本”构造函数。

public class MyClass
{
    private MyClass(object data1, string data2) { }

    public MyClass(object data1) : this(data1, null) { }

    public MyClass(string data2) : this(null, data2) { }

    public MyClass() : this(null, null) { }
}

我喜欢cache add语句中的赋值,我使用了空合并运算符将该语法用于延迟加载的属性,这在我之前从未出现过,现在可以在常规方法中使用。
克里斯·马里西奇

1
第一个示例似乎是SingletonFactory的示例?
Ankush Jain

最后一种情况的模式不必是private,但是private它很棒,因为没有人可以从外部使用该构造函数。我使用它为解析为相同中央代码的每个构造函数做出了稍微不同的行为。(例如public MyClass(string data2) : this(null, "Hello " + data2) { }:)同样使用C#6的{get;}属性,赋值代码仅在任何构造函数区域中有效,因此它们倾向于位于该private构造函数中。
5argon

35

正如Stefan,Adam和其他人所指出的那样,私有构造函数在不希望由类外部代码创建类的情况下很有用。单例,工厂,静态方法对象是能够限制类型构造对强制执行特定模式的示例。

为了回答您的问题的第二部分,即如果存在静态类,为什么需要单例:单例和静态类相等。

例如,单例类可以实现接口,而静态类则不能。单例对象可以作为参数传递给方法-使用静态类在不依靠包装对象或反射的情况下并不是一件容易的事。在某些情况下,您可能需要创建一个继承层次结构,其中一个(或多个)叶子类是单例的-静态类也不可能。再举一个例子,您可能有几个不同的单例,并且您可能想在运行时根据环境或配置参数实例化其中一个-静态类也无法实现。

了解语言功能并为工作选择合适的语言功能非常重要-它们之所以存在是有原因的。


关于单例与静态类的出色解释!我从中学习!FWIW,您实际上可以使用“静态初始化”来初始化非静态单例类。请参阅此官方文档。这是另一个让您一开始感到困惑并最终学到一些好东西的概念。:-)
RayLuo

15

有时您不应该实例化一个类。这使它变得明确,并在编译器级别强制执行。

单例只是一个用例。常量类,静态方法类和其他类型的模式指示类不应实例化。


1
仅出于完整性考虑:可以将类标记为静态,以确保仅允许使用静态成员,并且无法实例化该类。
flq 2010年

5

旨在在类中创建私有构造函数

  1. 限制要继承的类。

  2. 限制要实例化的类或创建多个实例/对象。

  3. 实现单例设计模式。

    public class TestPrivateConstructor
    {
        private TestPrivateConstructor()
        {  }
    
        public static int sum(int a , int b)
        {
            return a + b;
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            // calling the private constructor using class name directly 
            int result = TestPrivateConstructor.sum(10, 15);
            // TestPrivateConstructor objClass = new TestPrivateConstructor(); // Will throw the error. We cann't create object of this class
        }
    }
    

谢谢你 没有人指出它将限制继承的类。
巴桑塔·马蒂亚

3

您可以使用它来强制单例实例或创建工厂类。

静态方法可以调用私有构造函数来创建该类的新实例。

例如,一个单例实例:

public class Foo
{

  private Foo (){}

  private Foo FooInstance {get;set;}

  public static Foo GetFooInstance ()
  {
    if(FooInstance == null){
      FooInstance = new Foo();
    }

    return FooInstance;
  }

}

这仅允许创建该类的一个实例。


2

好吧,如果您的唯一目标是不希望实例化它,则使其成为静态就足够了。

如果,otoh,您只是不想在类之外实例化它(也许您只希望用户通过在类上使用静态工厂来获得一个),那么您需要一个私有ctor来允许那些可公开访问的static工厂实例化它。

从历史上讲,请记住,使类静态化并不总是存在的。在将static关键字应用于类之前,将ctor私有化是使其变得不可实例化的一种方法(这是一个词吗?)。


1

关于单例-单例是一种设计模式,当环境和需求满足使用该模式的类似动机时使用;静态类是一种语言功能。

正如LBushkin的答案所讨论的,虽然使用静态类可以满足使用Singleton的某些目标,但是Singleton的特定实现可能会超出静态类的功能集。


0

如果该类仅具有私有构造函数,则无法从外部实例化该类。

您还可以使用具有不同签名的私有构造函数和公共构造函数。


0

如果要为类创建工厂,则可以使用私有构造函数,并向类本身添加一些静态“ factory”方法来创建类。

一个示例是Graphics类,它具有From *方法。


0

私有构造函数是一个特殊的实例构造函数。在某些情况下,当我们创建一个仅具有静态成员的类时,就会使用该类,因此创建此类的实例是无用的,这就是私有构造函数起作用的地方。

如果一个类具有一个或多个私有构造函数而没有公共构造函数,则其他类(嵌套类除外)无法创建该类的实例。

例:

class LogClass {

  public static double e = Math.E;  //2.71828

  // Private Constructor:
  private LogClass() { 

 }  
}

空构造函数的声明阻止自动生成较少参数的构造函数。

如果未在构造函数中使用access修饰符,则默认情况下它仍将是私有的。了解更多:https//qawithexperts.com/tutorial/c-sharp/32/private-constructor-in-c-sharp

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.