静态字段初始值设定项不在实例构造函数之前运行

Bra*_*ner 5 c#

我有以下课程:

\n\n
public class AssignmentStatusCode \n{\n\n    public static AssignmentStatusCode Pending { get; } = new AssignmentStatusCode("P");\n\n    public static AssignmentStatusCode Rejected { get; } = new AssignmentStatusCode("R");\n\n    public static AssignmentStatusCode Approved { get; } = new AssignmentStatusCode("A");\n\n\n    public static implicit operator string(AssignmentStatusCode assignmentStatusCode)\n    {\n        return assignmentStatusCode.Value;\n    }\n\n    private static readonly HashSet<string> ValidStatusCodes = new HashSet<string>(new[] { "A", "R", "P" });\n\n    public AssignmentStatusCode(string value)\n    {\n        if (!ValidStatusCodes.Contains(value))\n        {\n            throw new ArgumentOutOfRangeException(nameof(value),\n                                                  $"Value must be {string.Join(", ", ValidStatusCodes.Select(c => $"\'{c}\'"))}.");\n        }\n\n        Value = value;\n    }\n\n    public string Value { get; }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

当我使用 创建此类的实例时var a = new AssignmentStatusCode("A"),会在实例构造函数的检查NullReferenceException中抛出a 。if调试表明ValidStatusCodesnull

\n\n

ValidStatusCodes上面有一个静态初始化程序。

\n\n

根据 C# 规范:

\n\n
\n

如果类中存在静态构造函数 (\xc2\xa710.12),则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,静态字段初始值设定项将在首次使用该类的静态字段之前的依赖于实现的时间执行

\n
\n\n

为什么我的静态字段在构造函数中访问之前没有被初始化?我有一种感觉,有一些非常简单的事情被我掩盖了,但我花了太多时间调试它,却没有任何进展;是时候寻求帮助了。

\n\n
\n\n

显然,如果我更仔细地阅读规范,我会在上面引用的段落开头注意到这一点,这是我的问题的根源。

\n\n
\n

10.5.5.1 静态字段初始化 类的静态字段变量初始值设定项对应于一系列赋值,这些赋值 按照它们在类声明中出现的文本顺序执行。如果类中存在静态构造函数 (\xc2\xa710.12),则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,静态字段初始值设定项将在首次使用该类的静态字段之前的依赖于实现的时间执行

\n
\n\n

感谢大家的帮助。

\n

Dav*_*ave 4

静态字段和属性按照它们在类中出现的顺序进行初始化。

C# 规范

去引用:

类的静态字段变量初始值设定项对应于一系列赋值,这些赋值按它们在类声明中出现的文本顺序执行。

另外为了完整性:

如果类中存在静态构造函数,则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,静态字段初始值设定项将在首次使用该类的静态字段之前的依赖于实现的时间执行

有人在评论中正确指出,因此这没有提到属性,只是提到了字段。我想说,自动属性是私有字段和具有 get 和 set 访问器的属性的语法糖,这只是更多的糖,因此具有 Get() 和 Set(value) 方法。因此,上述内容确实适用于属性,唯一的警告是我不知道编译器在哪里以及如何对这些支持字段进行排序。

您可以使用依赖于初始化字段之后的字段的构造函数来初始化 Pending、Rejected 和 Accepted 字段。

要么把你的哈希集字段放在第一位,这样它就会首先被初始化。或者我认为更好的方法是使用静态构造函数来初始化所有这些,以便您可以清楚地看到每个的顺序和依赖关系变得更清晰。另请参阅之前有关自动属性以及编译器存储私有支持字段的位置的注释,使用静态构造函数并完全相信它们获得适当值设置的顺序会更加相关