C#中静态构造函数/初始化器的顺序 [英] Order of static constructors/initializers in C#

查看:209
本文介绍了C#中静态构造函数/初始化器的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在工作C#应用程序时,我刚刚注意到,在几个地方,静态初始化程序相互依赖关系如下:

 静态私有列表< int> a = new List< int>(){0}; 
static private List< int> b = new List< int>(){a [0]};

没有任何特别的工作。这只是运气吗? C#有规则来解决这个问题吗?



编辑:(re:Panos)在一个文件中,词法顺序似乎是王者?在文件中怎么样?



在看来,我尝试了这样的循环依赖:

  static private List< int> a = new List< int>(){b [0]}; 
static private List< int> b = new List< int>(){a [0]};

并且程序运行不一样(测试套件全盘失败,

解决方案

这似乎取决于行的顺序。此代码的作用如下:

  static private List< int> a = new List< int>(){1}; 
static private List< int> b = new List< int>(){a [0]};

,而此代码不起作用(它抛出一个 NullReferenceException

  static private List< int> a = new List< int>(){b [0]}; 
static private List< int> b =新List< int>(){1};

所以,显然没有关于循环依赖的规则。但是,编译器不会抱怨,但是编译器并不抱怨...






编辑 - 跨文件发生了什么?如果我们声明这两个类:

  public class A {
public static List< int> a = new List< int>(){B.b [0]};
}
public class B {
public static List< int> b = new List< int>(){A.a [0]};
}

并尝试使用以下代码访问它们:

  try {Console.WriteLine(Bb); } catch(Exception e){Console.WriteLine(e.InnerException.Message。); } 
try {Console.WriteLine(A.a); } catch(Exception e){Console.WriteLine(e.InnerException.Message); }
try {Console.WriteLine(B.b); } catch(Exception e){Console.WriteLine(e.InnerException.Message);

我们得到这个输出:

 'A'的类型初始化器抛出异常。 
对象引用未设置为对象的实例。
'A'的类型初始化器抛出异常。

所以初始化 B 会导致异常在静态构造函数 A 中,剩下的字段 a 具有默认值(null)。由于 a null b 也不能初始化



如果我们没有循环依赖,一切都正常。






编辑:如果您没有阅读评论, Jon Skeet 提供了非常有趣的阅读:静态构造函数和类型初始值设置之间的差异


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).

解决方案

It seems to depend on the sequence of lines. This code works:

static private List<int> a = new List<int>() { 1 };
static private List<int> b = new List<int>() { a[0] };

while this code does not work (it throws a NullReferenceException)

static private List<int> a = new List<int>() { b[0] };
static private List<int> b = new List<int>() { 1 };

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:

public class A {
    public static List<int> a = new List<int>() { B.b[0] };
}
public class B {
    public static List<int> b = new List<int>() { A.a[0] };
}

and try to access them with this code:

try { Console.WriteLine(B.b); } catch (Exception e) { Console.WriteLine(e.InnerException.Message.); }
try { Console.WriteLine(A.a); } catch (Exception e) { Console.WriteLine(e.InnerException.Message); }
try { Console.WriteLine(B.b); } catch (Exception e) { Console.WriteLine(e.InnerException.Message); }

we are getting this output:

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.

So the initialization of B causes an exception in static constructor A and lefts field a with the default value (null). Since a is null, 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.

这篇关于C#中静态构造函数/初始化器的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆