我有一个ASP.NET网络应用程序,它开始显示一些非常奇怪的行为。这是一些示例代码:
// in Bar.cs
public class Bar {
public static Baz baz = Something.Step2();
}
// in Global.asax
public void Application_Start(...) {
Something.Step1();
}
故事的简短版本是这样的:在某些机器上,Something.Step2在Something.Step1之前执行并抛出一个不可处理的异常。在其他计算机上,Step1在Step2之前正确执行。 Global.asax及其使用的所有对象根本不会引用Bar。
什么时候静态字段应该相对于其他编程元素执行?为什么两台机器(Win7 64位,包括.NET 4.0,相同的IIS版本等)以不同的顺序执行操作?订单在每台机器上也是一致的。在我的机器上,总是在Step1之前执行Step2,但是在我的同事的机器上,总是在Step2之前执行Step1。
非常感谢。
更新我找到了访问静态字段的根本原因。我的示例中的“Bar”类实际上是一个自定义身份验证模块,并在web.config中作为System.webServer下的Authentication处理程序引用。如果我从web.config中删除该行,我的系统首先调用Step1,从不调用Step2。我的问题巧妙地改为:“为什么web.config导致我的静态初始化器被触发,为什么它会在Application_Start执行之前触发它们?”
答案 0 :(得分:7)
静态字段初始值设定项,当您没有静态构造函数时,会在第一次访问之前的“依赖于实现”时间进行初始化。这意味着它们可以随时初始化 - 您不能依赖首次使用Bar.Baz
时Bar
的初始化。
向Bar
添加静态构造函数会将此行为更改为您所期望的更多内容。
有关详细信息,请阅读C#语言规范10.5.5.1节:
10.5.5.1静态字段初始化
类的静态字段变量初始值设定项对应于按照它们出现在类声明中的文本顺序执行的赋值序列。如果类中存在静态构造函数(第10.12节),则在执行该静态构造函数之前立即执行静态字段初始值设定项。否则,静态字段初始化器在第一次使用该类的静态字段之前的实现相关时间执行。
另外,有关静态构造函数的详细信息,请参见10.2:
封闭类类型的静态构造函数在给定的应用程序域中最多执行一次。静态构造函数的执行由应用程序域中发生的以下第一个事件触发:
·创建了类类型的实例。
·引用了类类型的任何静态成员。
话虽如此,如果需要确定性初始化,我强烈建议将静态构造函数添加到Something
,并在那里正确进行初始化。除了在这种情况下提供初始化顺序的保证之外,它还会阻止另一个类使用Something
导致您的代码在将来中断。