Jon Skeet对Singleton的澄清


214
public sealed class Singleton
{
    Singleton() {}

    public static Singleton Instance
    {
        get
        {
            return Nested.instance;
        }
    }

    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested() {}
        internal static readonly Singleton instance = new Singleton();
    }
}

我希望在当前的C#应用​​程序中实现Jon Skeet的Singleton模式

我对代码有两个疑问

  1. 如何访问嵌套类内部的外部类?我的意思是

    internal static readonly Singleton instance = new Singleton();

    是所谓的关闭吗?

  2. 我无法理解此评论

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit

    此评论对我们有什么建议?


12
哈哈,我以为我曾说过,这让我有点担心,哈哈...原来是另一个约翰·诺兰
约翰·安东尼·丹尼尔·诺兰

14
人们普遍接受两件事:太阳从东方升起,乔恩·斯基特永远是对的。但我仍不确定前者:P
akhil_mittal'1

2
@ thepirat000-如果他只是SO / Meta的参与者,我可能会不同意,但是他在编程的实际世界中确实具有足够的影响力,这可能实际上是合法的-我敢肯定有人在某一点或另一点创建了它。
赛马会

8
这个问题的分类法正在meta上讨论。
BoltClock

Answers:


359
  1. 不,这与闭包无关。嵌套类可以访问其外部类的私有成员,包括此处的私有构造函数。

  2. 阅读有关beforefieldinit的文章。您可能会或可能不会想要no-op静态构造函数-这取决于您需要什么懒惰来保证。您应该知道,.NET 4 稍微改变了实际的类型初始化语义(仍在规范内,但比以前更懒)。

您是否真的需要这种模式?您确定无法摆脱:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();
    public static Singleton Instance { get { return instance; } }

    static Singleton() {}
    private Singleton() {}
}

12
@Anindya:不,很好。您可能希望通过电子邮件发送给JetBrains投诉:)
Jon Skeet

2
@JonSkeet,我刚刚向JetBrains提出了对此的担忧(#RSRP-274373)。让我们看看他们能想到什么。:)
Anindya Chatterjee 2011年

3
@月亮:你没有。单例在AppDomain的生存期内。
乔恩·斯基特

2
@JonSkeet有没有理由不使用Lazy<T>它,而不必为魔术BeforeFieldInit副作用声明静态构造函数?
Ed T

3
FieldBeforeInitMahaBharataMicrosoft
阿米特·库马尔·戈什

49

关于问题(1):乔恩(Jon)的回答是正确的,因为他通过不公开或内部:-)隐式地将“嵌套”类标记为私有。您也可以通过添加“ private”来明确地执行此操作:

    private class Nested

关于问题(2):基本上,关于beforeinitfield类型初始化的文章告诉您的是,如果没有静态构造函数,则运行时可以在任何时候(但在使用它之前)对其进行初始化。如果确实有静态构造函数,则静态构造函数中的代码可能会初始化字段,这意味着仅在要求输入类型时才允许运行时初始化字段。

因此,如果您不希望运行时在使用字段之前“主动”初始化字段,请添加静态构造函数。

无论哪种方式,如果您要实现单例,要么希望它初始化尽可能懒,而不是在运行时认为它应该初始化变量时不希望这样做–或者您可能不在乎。根据您的问题,我想您希望他们尽可能晚。

乔恩(Jon)关于单例(singleton)的帖子引起了人们的注意,这是IMO的基本问题。哦,还有疑问:-)

我想指出的是,他标记为“错误”的他的单身#3实际上是正确的(因为lock自动暗示退出时存在内存障碍)。当您多次使用实例时,它也应该比单例#2更快(或多或少是单例的要点:-))。因此,如果您确实需要一个懒惰的单例实现,那么我可能会这样做-原因很简单:(1)每个读取您的代码的人都非常清楚发生了什么,(2)您知道将会发生什么有例外。

万一您想知道:我永远不会使用Singleton#6,因为它很容易导致死锁和带有异常的意外行为。有关详细信息,请参见:惰性的锁定模式,特别是ExecutionAndPublication。


62
Regarding question (1): The answer from Jon is correct ...乔恩·斯基特(Jon Skeet)总是正确的..
2013年

72
尝试回答Jon Skeet已回答的有关Jon Skeet问题的加分。
瓦尔德特罗

8
@valdetero哈哈哈。这...哈哈哈+1
秋千
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.