ChatGPT解决这个技术问题 Extra ChatGPT

由 Jon Skeet 澄清的 Singleton

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's Singleton pattern

我对代码有两个疑问

如何访问嵌套类中的外部类?我的意思是内部静态只读 Singleton instance = new Singleton();有什么叫做闭包吗?我无法理解这条评论 // 显式静态构造函数告诉 C# 编译器 // 不要将类型标记为 beforefieldinit 这个评论对我们有什么建议?

哈哈,我以为我说过这有点担心哈哈……原来是另一个约翰·诺兰
@thepirat000 - 如果他只是 SO/Meta 的参与者,我可能不同意,但他在实际编程世界中确实有足够的影响力,这可能实际上是合法的 - 我确信有人在某个时候创建了它.
meta 正在讨论此问题的分类。

S
Sebastian Krysmanski

不,这与闭包无关。嵌套类可以访问其外部类的私有成员,包括此处的私有构造函数。阅读我关于 beforefieldinit 的文章。您可能需要也可能不需要无操作静态构造函数 - 这取决于您需要什么懒惰保证。您应该知道 .NET 4 在一定程度上改变了实际的类型初始化语义(仍在规范范围内,但比以前更懒惰)。

你真的需要这种模式吗?你确定你不能逃脱:

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

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

@Anindya:不,没关系。不过,您可能想给 JetBrains 发邮件投诉 :)
@JonSkeet,我刚刚向 JetBrains 提出了对此的担忧(# RSRP-274373)。让我们看看他们能想出什么。 :)
@Moons:你没有。单例在 AppDomain 的持续时间内存在。
@JonSkeet 有什么理由不使用 Lazy<T> 以便您不必为神奇的 BeforeFieldInit 副作用声明静态构造函数?
FieldBeforeInit 是来自 MicrosoftMahaBharata
D
Dog Ears

关于问题(1):乔恩的回答是正确的,因为他通过不公开或内部的方式将“嵌套”类隐式标记为私有:-)。您也可以通过添加“私人”来明确地做到这一点:

    private class Nested

关于问题(2):基本上the post about beforeinitfieldtype initialization告诉你的是,如果你没有静态构造函数,运行时可以随时初始化它(但在你使用它之前)。如果您确实有静态构造函数,则静态构造函数中的代码可能会初始化字段,这意味着运行时仅在您请求类型时才允许初始化字段。

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

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

这让 Jon 关于 singleton 的帖子遇到了问题,这是 IMO 这个问题的基本主题。哦,还有疑问:-)

我想指出他标记为“错误”的单例#3 实际上是正确的(因为锁定自动为 implies a memory barrier on exit)。当您多次使用实例时,它也应该比单例#2 更快(这或多或少是单例的要点:-))。所以,如果你真的需要一个惰性单例实现,我可能会选择那个——原因很简单:(1)每个阅读你的代码的人都非常清楚发生了什么,(2)你知道会发生什么有例外。

如果您想知道:我永远不会使用单例#6,因为它很容易导致死锁和异常行为。有关详细信息,请参阅:lazy's locking mode,特别是 ExecutionAndPublication。


Regarding question (1): The answer from Jon is correct ... Jon Skeet总是正确....
尝试回答 Jon Skeet 已经回答的 Jon Skeet 问题的额外分数。
@valdetero 哈哈哈。这……哈哈哈+1