关于c#:单身人士由Jon Skeet澄清

Singleton by Jon Skeet clarification

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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();

    有什么叫封闭吗?

  • 我无法理解这个评论

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

    这个评论对我们有什么建议?


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

  • 阅读我关于beforefieldinit的文章。您可能需要也可能不需要no-op静态构造函数——这取决于您需要什么样的惰性保证。您应该知道.NET4会稍微改变实际的类型初始化语义(仍然在规范中,但比以前更慢)。

  • 不过,你真的需要这种模式吗?您确定无法摆脱:

    1
    2
    3
    4
    5
    6
    7
    8
    public sealed class Singleton
    {
        private static readonly Singleton instance = new Singleton();
        public static Singleton Instance { get { return instance; } }

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


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

    1
        private class Nested

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

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

    不管怎样,如果您正在实现单例,您要么希望它初始化得尽可能慢,而不是当运行时认为它应该初始化您的变量时——或者您可能不在乎。从你的问题来看,我想你希望他们尽可能晚。

    这让我想起了乔恩关于辛格尔顿的文章,在我看来,这是这个问题的潜在主题。哦,还有疑问:—)

    我想指出的是,他标记为"错误"的单件3实际上是正确的(因为lock's自动暗示了退出时的内存屏障)。当您多次使用实例时,它也应该比singleton 2快(这或多或少是singleton的点:-)。因此,如果您真的需要一个懒惰的单例实现,我可能会选择这个实现——原因很简单:(1)对于每个阅读代码的人来说,这是非常清楚的;(2)您知道除了异常情况外会发生什么。

    如果你想知道:我永远不会使用singleton 6,因为它很容易导致死锁和异常情况下的意外行为。有关详细信息,请参见:Lazy的锁定模式,特别是执行和发布。