c# - 在 Main() 之前调用的隐式静态构造函数
问题描述
我有以下一段代码。
class Program
{
static void Main(string[] args)
{
Enterprise.Initialize("Awesome Company");
// Assertion failed when constructor of 'Reg' class is disabled.
Debug.Assert(Reg.Root == @"Software\Awesome Company");
}
}
public static class Enterprise
{
// Static Properties.
public static string Company
{
get;
private set;
}
// Static Methods.
public static void Initialize(string company)
{
Company = company;
}
}
public class Reg
{
public static string Root = $@"Software\{Enterprise.Company}";
// ctor.
static Reg()
{
// Assertion failed when this constructor is disabled.
}
}
执行时,断言通过。Reg
但是,当类的构造函数被禁用时,断言失败。仔细一看,我发现Reg
class 的隐式构造函数是 before 调用的Main()
。如果Reg
类的构造函数是显式定义的,它会在之后被调用Main()
。
为什么隐式和显式构造函数之间存在这种差异?
解决方案
这是链式静态类初始化的一个怪癖。
15.5.6.2 静态字段初始化
类的静态字段变量初始化器对应于一系列赋值,它们按照它们在类声明中出现的文本顺序执行(第 15.5.6.1 节)。在部分类中,“文本顺序”的含义由 §15.5.6.1 指定。如果类中存在静态构造函数(第 15.12 节),则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,静态字段初始化器在第一次使用该类的静态字段之前的依赖于实现的时间执行。
特别注意最后一部分,这是您的问题,如果您没有静态构造函数,则无法控制该字段的初始化时间。在您的测试用例中,它们在您调用之前被初始化Enterprise.Initialize
简而言之,你不应该依赖这些规则,很容易犯错误,很可能会导致奇怪的问题。
推荐阅读
- reactjs - Gatsby 的内部路由器存在特殊字符问题
- python - 如果 str 在某处有诸如点或破折号之类的分隔符,如何添加 str 和 str?
- vaadin - 从 Vaadin (20) Flow 项目中的模板文件初始化路由器事件
- html - 继承模板时以编程方式更改 html 标记
- highcharts - 根据 x 和 y 开始、结束值为每个区域填充颜色
- r - 使用 grid.grab() 在 R 中保存输出图不起作用
- linux-kernel - kzalloc 整数数组 vs kmalloc 和 for 循环中的零元素
- javascript - 我可以为这个 SVG 旋钮设置动画吗?
- dart - 为什么飞镖允许非未来返回异步?
- rest - RESTful 服务。不同的响应和请求模式