C#中的静态构造函数/初始化程序的顺序
在使用C#应用程序时,我只是注意到在几个地方静态初始化程序彼此依赖,如下所示:
static private List a = new List() { 0 }; static private List b = new List() { a[0] };
没有做任何有用的特殊工作。 这只是运气吗? C#有解决这个问题的规则吗?
编辑:( re:Panos)在一个文件中,词汇顺序似乎是王道? 跨文件怎么样?
在寻找我尝试这样的周期性依赖:
static private List a = new List() { b[0] }; static private List b = new List() { a[0] };
并且该程序没有运行相同(测试套装全面失败,我没有看得更远)。
它似乎取决于线的顺序。 此代码有效:
static private List a = new List () { 1 }; static private List b = new List () { a[0] };
虽然这段代码不起作用(它抛出NullReferenceException
)
static private List a = new List () { b[0] }; static private List b = new List () { 1 };
所以,显然没有关于周期性依赖的规则。 然而,奇怪的是编译器没有抱怨……
编辑 – “跨文件”发生了什么? 如果我们声明这两个类:
public class A { public static List a = new List () { Bb[0] }; } public class B { public static List b = new List () { Aa[0] }; }
并尝试使用以下代码访问它们:
try { Console.WriteLine(Bb); } catch (Exception e) { Console.WriteLine(e.InnerException.Message.); } try { Console.WriteLine(Aa); } catch (Exception e) { Console.WriteLine(e.InnerException.Message); } try { Console.WriteLine(Bb); } catch (Exception e) { Console.WriteLine(e.InnerException.Message); }
我们得到这个输出:
The type initializer for 'A' threw an exception. Object reference not set to an instance of an object. The type initializer for 'A' threw an exception.
因此, B
的初始化会导致静态构造函数A
和lefts字段a
的exception具有默认值(null)。 由于a
为null
,因此b
也无法正确初始化。
如果我们没有周期性依赖,一切正常。
编辑:为了防止你没有阅读评论, Jon Skeet提供了一个非常有趣的阅读: 静态构造函数和类型初始值设定项之间的区别 。
有关规则,请参阅C#规范的10.4节 :
初始化类时,首先将该类中的所有静态字段初始化为其默认值,然后以文本顺序执行静态字段初始值设定项。 同样,当创建类的实例时,首先将该实例中的所有实例字段初始化为其默认值,然后以文本顺序执行实例字段初始化程序。 具有可变初始值设定项的静态字段可以在其默认值状态下被观察到。 然而,作为一种风格问题,强烈建议不要这样做。
换句话说,在您的示例中,’b’被初始化为其默认状态(null),因此在’a’的初始化程序中对它的引用是合法的,但会导致NullReferenceException。
这些规则与Java不同(请参阅JLS for Java关于前向引用的规则的第8.3.2.3节,这些规则更具限制性)。
我个人会删除静态初始化程序,因为它不清楚并添加一个静态构造函数来初始化这些变量。
static private List a; static private List b; static SomeClass() { a = new List () { 0 }; b = new List () { a[0] }; }
然后你不必猜测发生了什么,你的意图是明确的。
是的,你很幸运。 C#似乎按照它在类中出现的顺序执行代码。
static private List a = new List () { 0 }; static private List b = new List () { a[0] };
会工作,但……
static private List b = new List () { a[0] }; static private List a = new List () { 0 };
将失败。
我建议将所有依赖项放在一个地方,静态构造函数就是这个地方。
static MyClass() { a = new List() { 0 }; b = new List () { a[0] }; }