如果静态只读成员调用静态方法来获取值,它是否同步完成?

nev*_*gqs 11 c# static synchronous

鉴于:

public class MyClass
{
    private static readonly Dictionary<string,int> mydict = CreateDictionary();

    private static Dictionary<string,int> CreateDictionary() { ... }
}
Run Code Online (Sandbox Code Playgroud)

这是同步完成的吗?(即可以两次快速实例化MyClass原因CreateDictionary()被调用两次?

xan*_*tos 10

是的,这是线程安全的.C#静态构造函数线程是否安全?

在创建类的任何实例或访问任何静态成员之前,保证每个应用程序域只运行一次静态构造函数.http://msdn.microsoft.com/en-us/library/aa645612.aspx

静态字段初始化是静态构造函数的一部分.该领域的事实readonly不会改变任何事情

根据要求提供一些IL代码(取自Try Roslyn http://goo.gl/ayIMG0)

.method private hidebysig specialname rtspecialname static 
    void .cctor () cil managed 
{
    // Method begins at RVA 0x205f
    // Code size 11 (0xb)
    .maxstack 8

    IL_0000: call class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32> MyClass::CreateDictionary()
    IL_0005: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string, int32> MyClass::mydict
    IL_000a: ret
} // end of method MyClass::.cctor
Run Code Online (Sandbox Code Playgroud)

其中.cctor是静态构造函数的特殊名称.呼叫CreateDictionary和分配mydict非常明显.

  • @CriketerOnSO编写一个类,在那里放置一个带字段初始化程序的静态字段,编译它,在"IL"模式下用IlSpy查看它.您将在初始化代码中看到一个静态构造函数. (2认同)

Eri*_*ert 8

接受的答案是正确的; 初始化将发生零次或一次但不会发生两次.但我想补充一点.在您的示例中,CLR和C#语言保留了比您预期更早地初始化字段的权限.如果你写:

public class MyClass
{
    private static readonly Dictionary<string,int> mydict = CreateDictionary();
    static MyClass() {}
Run Code Online (Sandbox Code Playgroud)

然后CLR和C#保证在调用第一个静态方法MyClass或MyClass创建第一个实例时初始化该字段.如果省略静态构造函数,则允许CLR和C#(但不是必需)在这些事件之前的任何时间初始化字段.特别是,假设您有一个M调用静态方法的方法MyClass.CLR可能决定运行MyClass.mydict 何时Mjitted的静态初始化程序,而不是在M实际调用静态方法时.这可以在一些罕见的情况下导致令人惊讶的结果.

对beforefieldinit优化进行Web搜索以获取更多详细信息.Jon Skeet有一篇很好的文章.