C# 中静态构造函数/初始化程序的顺序
在开发 C# 应用程序时,我注意到在几个地方静态初始化程序相互依赖,如下所示:
static private List<int> a = new List<int>() { 0 };
static private List<int> b = new List<int>() { a[0] };
无需执行任何有效的特殊操作。 这只是运气吗? C# 有解决这个问题的规则吗?
编辑:(回复:Panos)在文件中词汇顺序似乎才是王道? 跨文件怎么样?
在查看时,我尝试了这样的循环依赖:
static private List<int> a = new List<int>() { b[0] };
static private List<int> b = new List<int>() { a[0] };
并且程序运行不一样(测试套件全面失败,我没有进一步查看)。
While working on a C# app I just noticed that in several places static initializers have dependencies on each other like this:
static private List<int> a = new List<int>() { 0 };
static private List<int> b = new List<int>() { a[0] };
Without doing anything special that worked. Is that just luck? Does C# have rules to resolve this?
Edit: (re: Panos) In a file lexical order seems to be king? what about across files?
In looking I tried a cyclical dependency like this:
static private List<int> a = new List<int>() { b[0] };
static private List<int> b = new List<int>() { a[0] };
and the program didn't run the same (the test suit failed across the board and I didn't look further).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
有关规则,请参阅 C# 规范第 10.4 节这里:
换句话说,在您的示例中,“b”被初始化为其默认状态(null),因此“a”的初始化程序中对它的引用是合法的,但会导致 NullReferenceException。
这些规则与 Java 的规则不同(请参阅 第 8.3.2.3 节Java 关于前向引用的规则的 JLS,其限制性更强)。
See section 10.4 of the C# spec for the rules here:
So in other words, in your example 'b' is initialized to its default state (null) and so the reference to it in the initializer of 'a' is legal but would result in a NullReferenceException.
These rules are different to Java's (see section 8.3.2.3 of the JLS for Java's rules about forward references, which are more restrictive).
这似乎取决于行的顺序。 这段代码有效:
虽然这段代码不起作用(它抛出一个 NullReferenceException),
所以,显然不存在循环依赖的规则。 然而,奇怪的是编译器不会抱怨......
编辑-“跨文件”发生了什么? 如果我们声明这两个类:
并尝试使用以下代码访问它们:
我们将得到以下输出:
因此
B
的初始化会导致静态构造函数A
中出现异常,并留下异常字段a
具有默认值 (null)。 由于a
为null
,因此b
也无法正确初始化。如果我们没有循环依赖,一切都会正常进行。
编辑:以防万一您没有阅读评论,Jon Skeet 提供了非常有趣的阅读:静态构造函数和类型初始值设定项之间的区别。
It seems to depend on the sequence of lines. This code works:
while this code does not work (it throws a
NullReferenceException
)So, obviously no rules for cyclical dependency exist. It's peculiar however that the compiler does not complain...
EDIT - What's happening "across files"? If we declare these two classes:
and try to access them with this code:
we are getting this output:
So the initialization of
B
causes an exception in static constructorA
and lefts fielda
with the default value (null). Sincea
isnull
,b
can not also be initialized properly.If we do not have cyclical dependencies, everything works fine.
EDIT: Just in case you didn't read the comments, Jon Skeet provides a very interesting reading: The differences between static constructors and type initializers.
就我个人而言,我会摆脱静态初始化程序,因为它不清楚,并添加静态构造函数来初始化这些变量。
这样你就不必猜测发生了什么,你的意图就很清楚了。
Personally I would get rid of the static initializers since it isn't clear and add a static constructor to initialize these variables.
Then you don't have to guess what is going on and you're being clear in your intentions.
是的,你很幸运。 C# 似乎按照代码在类中出现的顺序执行代码。
会起作用,但是......
会失败。
我建议将所有依赖项放在一处,静态构造函数就是执行此操作的位置。
Yes, you were lucky. C# appears to execute the code in the order it appears in the class.
Will work but ...
Will fail.
I would recommend putting all your dependencies in one place, the static constructor is the place for this.