使用静态构造函数的单例实现惰性

Singleton implementation laziness with static constructor

Jon Skeet 建议 in his singleton implementation that if you require the maximum laziness for your singleton 你应该添加一个静态构造函数,这将使编译器将类型标记为 beforefieldinit。

但是,我做了一些测试,它似乎更懒没有 beforefieldinit。

代码示例(私有构造函数调用输出到控制台并验证字段是否已初始化:

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    public static string Stub()
    {
        return "123";
    }

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    //static Singleton()
    //{
    //}
    private Singleton()
    {
        Console.WriteLine("private ctor");
    }

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

当我调用 Singleton.Stub() 时,私有构造函数没有被命中,当我取消注释静态构造函数时,私有构造函数总是被调用。

这是我能追踪到的由静态构造函数造成的唯一区别。

在我试图理解 beforefieldinit 有什么区别的过程中,我也阅读了 Skeet 的回答 in this post 尝试将 false 传递给 DoSomething() - 无论有没有静态构造函数,私有构造函数都没有打电话。

public static void DoSomething(bool which)
{
    if (which)
    {
        var a = Singleton.Stub();
    }
    else
    {
        Faketon.Stub();
    }
}

When I call Singleton.Stub() the private constructor is not being hit, when I uncomment the static ctor private constuctor is always called.

不清楚这里 which 的值是什么,但基本上你有四种情况:

  • 静态构造函数,Singleton.Stub 已调用:类型初始值设定项保证 运行
  • 静态构造函数,Singleton.Stub 未调用:类型初始化程序保证不会 运行
  • 没有静态构造函数,Singleton.Stub 调用:类型初始值设定项可能 运行,但不保证
  • 没有静态构造函数,Singleton.Stub 未被调用:类型初始值设定项可能 运行,但不保证

最后两种情况的区别仅在于,如果将 Singleton.Stub 更改为使用静态字段,则第三种情况变为 "type initializer is guaranteed to run"。