【发布时间】:2019-02-14 14:37:42
【问题描述】:
我有以下课程:
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") 创建此类的实例时,NullReferenceException 会在实例构造函数的if 检查中抛出。调试表明ValidStatusCodes是null。
ValidStatusCodes 上有一个静态初始化器。
根据 C# 规范:
如果类中存在静态构造函数(第 10.12 节), 静态字段初始化器的执行发生在紧接之前 执行该静态构造函数。 否则,静态字段 初始化器在依赖于实现的时间执行 第一次使用该类的静态字段。
为什么我的静态字段在构造函数中被访问之前没有被初始化?我有一种感觉,我正在掩饰一些非常简单的事情,但是我花了太多时间调试它而没有任何进展;是时候寻求帮助了。
显然,如果我更仔细地阅读规范,我会在上面引用的段落的开头注意到这一点,这是我问题的根源。
10.5.5.1 静态字段初始化 类的静态字段变量初始化器对应于一系列赋值 按照它们在类中出现的文本顺序执行 声明。如果类中存在静态构造函数(第 10.12 节), 静态字段初始化器的执行发生在紧接之前 执行该静态构造函数。否则,静态字段 初始化器在依赖于实现的时间执行 首次使用该类的静态字段
感谢大家的帮助。
【问题讨论】:
-
在
public static AssignmentStatusCode Pending ...之前移动private static readonly HashSet<string> ValidStatusCodes ...应该可以工作。 -
要解释为什么 Alessandro 的答案会起作用,请参阅 C# 规范 (ECMA-334) 17.11:“如果一个类包含任何带有初始化器的静态字段,那么这些初始化器会在执行静态之前立即以文本顺序执行构造函数。”
-
啊,谢谢。我很久以前写过这个类,忘记了静态属性也通过构造函数。今天早上添加静态字段时,我也没有注意到它。这就是我错过的简单事情。
-
我认为您在这里没有遗漏任何内容。您只有一个静态字段。引用的文档文本没有告诉我们任何关于静态属性的信息。
标签: c#