【问题标题】:Static Class and Private Constructor静态类和私有构造函数
【发布时间】:2013-02-13 13:36:27
【问题描述】:

我无法理解这一点。我尝试在 VS2010 中做一个小例子,如下所示。

“因此创建静态类与创建仅包含静态成员和私有构造函数的类非常相似”

此语句是否意味着具有私有构造函数和一个或多个如下静态方法的类是静态类?我知道只有在类中提到静态关键字时,我们才称其为静态类。

另外,我们不能继承下面的类,也不能实例化这个类,对吧?

public class Base
{
    private Base() { Console.WriteLine(" I am from normal Base constructor"); }
    static void NewMethod() { Console.WriteLine("Hey I am from Static Base"); }
    public void New() { } 
}

【问题讨论】:

  • 仅静态成员一个或多个静态方法不同。

标签: c# .net static


【解决方案1】:

因此,创建静态类与创建仅包含静态成员和私有构造函数的类非常相似

此声明试图传达正确的想法,但未能如愿。静态类类似于只有静态成员和私有构造函数的类。这是一个具有静态成员和私有构造函数的类:

class X
{
    private X() {}
    public static X Y() { return new X(); }
}

但这根本不像一个静态类!该声明的作者似乎认为拥有私有构造函数会阻止您创建实例,但它当然不会。

更准确的说法是:

创建一个静态类很像创建一个既抽象又密封的类,并且不包含实例成员。

事实上,当 C# 编译器为静态类生成代码时,它正是这样做的:它将类标记为抽象(因此不能直接实例化)和密封(因此不能扩展) .

我注意到你自己声明一个抽象类和密封类是不合法的;在 C# 中这样做的唯一方法是创建一个静态类。

我会提请 MSDN 文档管理员注意该误导性句子。感谢您指出。

【讨论】:

  • 您好 Eric Lippert,非常感谢您花时间给我写信并让我理解。我知道,传达我的想法让我有点不舒服,你说得非常正确。再次感谢你。让我感到惊讶的一件事是,在看到您的声明“我注意到您自己声明一个抽象类和密封类是不合法的;在 C# 中这样做的唯一方法是创建一个静态类。”,当一直读到这句话上面一行,我赶紧去VS做了abstract and seal,报错了,正要回信给你,却发现你已经解决了
  • 所以我很高兴您解决并消除了我对此的所有疑问。 :) 非常感谢。干杯
  • @Divine:不客气。我已经与文档经理谈过了,他会考虑更新该页面以使其更加清晰。
  • @@Eric:再次感谢您。我非常感谢 :) 干杯
  • @Jowen:因为您发现它“与 OOP 相悖”而避免使用语言功能似乎很不幸;这是一个有用的功能。 OOP 是好的,因为这种编程风格降低了大型团队编写软件的成本,而不是因为它受到了编程之神的祝福。重要的是您的程序是正确的、可理解的、可维护的,并能解决真正的客户问题,而不是它们是 OOP 的漂亮示例。
【解决方案2】:

意思是:

public static class Foo
{
    public static void Bar() { }
}

本质上是一样的

public class Foo
{
    private Foo() { }
    public static void Bar() { }
}

因为如果类只有私有构造函数,就不能在类外实例化。

【讨论】:

  • 感谢您的快速示例,它很容易理解 :) 所以这意味着 1)我们也不能继承该类,对吗?我的意思是具有私有构造函数的类。 2)而且,这个带有私有构造函数的类可以有很多静态方法吗? 3) 你用什么术语来调用这样一个带有私有构造函数的类?你说的又是静态类? 4)上面有人说过,“仅包含静态成员与一个或多个静态方法不同”。这怎么可能?我无法理解其中的区别。
  • 1) 是的,您不能从只有私有构造函数的类继承。 2)是的,据我所知,一个类可以声明的方法数量没有限制,尽管您应该确保该类不会开始做太多事情(阅读单一责任原则)3)它本质上是“密封的”因为如果它只包含私有构造函数,它就不能被继承或实例化。 4)他们的意思是一个类可以有实例和静态方法,在这种情况下你不能有一个静态类,因为它不能包含实例方法。
  • 正确,就是这个意思。当然,这并不完全相同。例如,在第二种情况下,它可以说Foo variable = null;,或者定义一个方法void M(Foo foo) { }。此外,如果您不将其标记为sealed,则可以使用where T : Foo 等通用约束。
  • 一个实例构造函数都是private的非密封类,可以被嵌套的类继承。在上面的示例中,Foo 不包含嵌套类型。此外,private 构造函数可用于从类inside 实例化该类,但上述Foo 不包含new 对象表达式。
  • @TrevorPilley:非常感谢,您以我可以咀嚼的方式恰当地回答了我所有的问题 :)。我还有一个问题,虽然很傻。有一个明确表示密封的方法和有一个带有私有构造函数的方法有什么区别(留下私有构造函数或静态方法的优势)
【解决方案3】:

"此语句是否表示具有私有构造函数的类和一个或 更多像下面这样的静态方法是静态类吗?”

答案是否定的,一个区别在你从MSDN引用的那句话之后的下一句中解释:

使用静态类的好处是编译器可以检查 以确保不会意外添加任何实例成员。


这意味着您将在Class2 中得到编译器错误,如下所示。

public class Class1
{
    private Class1() { }
    public static void Method() { }
    private string member; // valid, but pointless
}

public static class Class2
{
    public static void Method() { }
    private string member; // error CS0708
}

更重要的是,虽然Class1有一个私有构造函数,但它仍然可能被实例化:

public class Class1
{
    private Class1() { }

    private static Class1 instance = new Class1();

    public static Class1 Instance
    {
        get { return instance; }
    }
}

另一方面,静态类可能永远不会被实例化。

【讨论】:

  • 嗨 Clemens,非常感谢您指出当类具有私有构造函数时仍然可以实例化。所以这就是他们称之为 Singleton 的东西?正确吗?
  • 你能告诉我这种带有私有构造函数的类的实例化何时发生的实时示例吗?
  • 我已经编辑了我的答案以展示Class1 将如何实现单例模式。您可以通过静态 Class1.Instance 属性访问单例实例。
  • var name = Class1.Instance.Name;。请注意,您声明的不是属性,而是公共字段。
  • 使用 get 或 set 访问器它是一个属性,没有它是一个字段。也许你的意思是auto-implemented properties,应该写成public string Name { get; set; }
【解决方案4】:

你不能继承,因为没有公共构造函数,只有一个私有构造函数存在。出于同样的原因,您不能创建实例。

在这个问题的范围内,它们可以被视为相同。你能称之为静态类吗?我认为正式你没有,因为它没有在类定义中标记为static。但从功能的角度来看,你可以称之为static

【讨论】:

  • 当然,不是真的 static。例如,您仍然可以使用var list = new List<Base>();var array = new Base[100];。在我的 cmets 中查看其他示例以了解其他问题。
【解决方案5】:

在您的示例中,可以调用 New() 方法的唯一方法是添加另一个方法以返回 Base 实例,因为 Base 不能被另一个类实例化。没有那个额外的方法使它在功能上与静态类相同。

【讨论】:

  • 虽然编译器不知道这一点。它仍然允许Base variable = null;var list = new List<Base>();public Base Method(Base parameter) { return null; } 之类的东西,where T : Base 形式的通用约束,以及许多其他对真正的static 类没有意义和不允许的构造。 (当然,如果您愿意,可以通过反射实例化 Base 并运行私有构造函数;static 类型不会发生这种情况,因为从框架中可以看出它是抽象的。)
【解决方案6】:

你从哪里得到的声明:

因此,创建静态类与创建类大致相同 只包含静态成员和私有构造函数

它想说的是你不能创建静态类的实例。

创建静态类的方法是使用static关键字。类中的所有成员也必须是静态的。

public static class MyStaticClass
{
      static MyStaticClass() { /* Constructor.  Optional. */ }
      public static void MyMethod() { ... }
      public static int MyProperty{ get; set; }
}

再次注意,您不能创建此类的实例。以下调用将无法编译:

new MyStaticClass();

【讨论】:

【解决方案7】:

静态类永远不能被实例化、参与继承或使用接口。但是一个类,即使具有私有构造函数,仍然可以继承,而静态类则不能。具有私有构造函数的类仍然可以实例化自身的实例。静态无法做到这一点。所以不,它们不一样。

我不明白为什么微软有时仍然不明白它创造了什么,因为他们是写那个描述的人(正如 Eric Lippert 提到的)?

另一个困惑是静态构造函数是私有的还是公共的?这将有助于解释行为,因为就像每个类中的默认公共构造函数一样,每个静态类也有一个默认构造函数。对我来说,这意味着静态构造函数将是公共的,但事实并非如此。它不能被访问或调用,并且可以被覆盖。

因为静态类在编译为密封的抽象类时会被翻译,这表明它的静态构造函数实际上只是另一个默认的公共类构造函数,没有参数,只能调用一次。我可能是错的。但如果是这样的话,整个私有构造函数的解释就没有意义了。

【讨论】:

    猜你喜欢
    • 2015-06-28
    • 1970-01-01
    • 2010-09-24
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多