为什么不首先调用静态构造函数,而在使用声明的变量时出现异常?

why Static constructors not called first and i got exception when use declared variable?

来自 MSDN

A static constructor is used to initialize any static data, or to perform a particular action that needs to be performed once only. It is called automatically before the first instance is created or any static members are referenced

MSDN Link

现在我的问题来了:

public static class DateFormat
{
    private static List<string> DateFormats = new List<string>();

    public static string DateSeparator  { get; set; } = "/";

    public static string Current { get; set; } = DateFormats[1]; // error here

    static DateFormat()
    {
        DateFormats.Add("yyyy{0}MM{0}dd HH{1}mm{1}ss");
        DateFormats.Add("yyyy{0}MM{0}dd hh{1}mm{1}ss");
    }
}

正如您在调用 DateFormats[1] 时看到的上面的错误

"The type initializer for 'DateFormat' threw an exception."

构造函数是否应该先调用静态构造函数?这样字典就会被填满,然后对使用它的变量的任何调用都可以。

此处记录了此行为:https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/static-constructors

具体来说,这一段:

If static field variable initializers are present in the class of the static constructor, they will be executed in the textual order in which they appear in the class declaration immediately prior to the execution of the static constructor.

由于静态字段变量初始值设定项确实存在,它们将在静态构造函数之前被初始化,这就是您看到该错误的原因:

public static string Current { get; set; } = DateFormats[1]; 

会在

之前执行
static DateFormat()
{
    DateFormats.Add("yyyy{0}MM{0}dd HH{1}mm{1}ss");
    DateFormats.Add("yyyy{0}MM{0}dd hh{1}mm{1}ss");
}

当然,DateFormats 列表在执行 DateFormats[1] 时仍然是空的。

要解决这个问题,只需在静态构造函数中初始化Current

public static class DateFormat
{
    static DateFormat()
    {
        DateFormats.Add("yyyy{0}MM{0}dd HH{1}mm{1}ss");
        DateFormats.Add("yyyy{0}MM{0}dd hh{1}mm{1}ss");

        Current = DateFormats[1];
    }

    private static List<string> DateFormats = new List<string>();

    public static string DateSeparator { get; set; } = "/";

    public static string Current { get; set; }
}

这就是所有语法糖的方式"translated":

static DateFormat()
{
    DateFormats = new List<string>();
    DateSeparator = "/";
    Current = DateFormats[1]; // at this point DateFormats is empty
    DateFormats.Add("yyyy{0}MM{0}dd HH{1}mm{1}ss");
    DateFormats.Add("yyyy{0}MM{0}dd hh{1}mm{1}ss");
}

不要混合使用内联初始化和构造函数中的代码。真让人头疼。 特别是如果 class 成员相互依赖。对于实例构造函数也是如此。