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

标签 c#

我有以下类(class):

public class AssignmentStatusCode 
{

    public static AssignmentStatusCode Pending { get; } = new AssignmentStatusCode("P");

    public static AssignmentStatusCode Rejected { get; } = new AssignmentStatusCode("R");

    public static AssignmentStatusCode Approved { get; } = new AssignmentStatusCode("A");


    public static implicit operator string(AssignmentStatusCode assignmentStatusCode)
    {
        return assignmentStatusCode.Value;
    }

    private static readonly HashSet<string> ValidStatusCodes = new HashSet<string>(new[] { "A", "R", "P" });

    public AssignmentStatusCode(string value)
    {
        if (!ValidStatusCodes.Contains(value))
        {
            throw new ArgumentOutOfRangeException(nameof(value),
                                                  $"Value must be {string.Join(", ", ValidStatusCodes.Select(c => $"'{c}'"))}.");
        }

        Value = value;
    }

    public string Value { get; }
}

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

ValidStatusCodes 有一个静态初始化器。

根据 C# 规范:

If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class.

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


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

10.5.5.1 Static field initialization The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration. If a static constructor (§10.12) exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class

谢谢大家的帮助。

最佳答案

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

C# Spec

引用:

The static field variable initializers of a class correspond to a sequence of assignments that are executed in the textual order in which they appear in the class declaration.

同时为了完整性:

If a static constructor exists in the class, execution of the static field initializers occurs immediately prior to executing that static constructor. Otherwise, the static field initializers are executed at an implementation-dependent time prior to the first use of a static field of that class

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

您使用依赖于字段初始化之后的字段的构造函数来初始化您的待定、拒绝和接受字段。

要么将您的哈希集字段放在第一位,以便它首先被初始化。或者我认为更好的方法是使用静态 ctor 来初始化所有这些,这样您就可以清楚地看到每个顺序和依赖关系变得更加清晰。还引用了前面关于自动属性和编译器存储私有(private)支持字段的位置的说明,使用静态 ctor 并完全相信它们获得适当值设置的顺序会更加中肯

关于c# - 静态字段初始值设定项未在实例构造函数之前运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54692923/

相关文章:

c# - Linq/ Entity Framework 中的对象和上下文有什么区别

c# - EF,代码优先 - 如何在插入时设置自定义 Guid 标识值

c# - 继承自一个类,这是做什么的?

c# - 在 DateTimeAxis 中定位轴标签

c# - 这是什么意思 "Detected time complexity: O(Y-X)"?

c# - 如何用增量数字替换之前包含一些字符的唯一字符串

c# - 如何读取 WCF 服务中的客户端证书?

c# - 异步与多线程

c# - 逗号和(小数)点 : Do they need different handling?

c# - 线程本地存储