[C# Tips] 有趣的类型静态构造器
这是C#中一个有趣的现象,也许您从中可以窥见些许CLR在构造类型时的行为,以及JIT编译的触发式编译过程。
看下面一段代码:
1 class Program
2 {
3 static void Main()
4 {
5 myValueType1 type1 = new myValueType1();
6 Console.WriteLine(myValueType1.myInt);
7 Console.WriteLine("**********************");
8 myValueType2 type2 = new myValueType2();
9 type2.myInt = 123;
10 Console.WriteLine(type2.myInt);
11 Console.WriteLine("**********************");
12 myValueType3 type3 = new myValueType3();
13 }
14 }
15
16 struct myValueType1
17 {
18 static myValueType1()
19 {
20 Console.WriteLine("Hello from myValueType1");
21 // myInt = 111;
22 }
23 public static Int32 myInt;
24 }
25
26 struct myValueType2
27 {
28 static myValueType2()
29 {
30 Console.WriteLine("Hello from myValueType2");
31 }
32 public Int32 myInt;
33 }
34
35 struct myValueType3
36 {
37 static myValueType3()
38 {
39 Console.WriteLine("Hello from myValueType3");
40 myInt = 333;
41 }
42 public static Int32 myInt;
43 }
2 {
3 static void Main()
4 {
5 myValueType1 type1 = new myValueType1();
6 Console.WriteLine(myValueType1.myInt);
7 Console.WriteLine("**********************");
8 myValueType2 type2 = new myValueType2();
9 type2.myInt = 123;
10 Console.WriteLine(type2.myInt);
11 Console.WriteLine("**********************");
12 myValueType3 type3 = new myValueType3();
13 }
14 }
15
16 struct myValueType1
17 {
18 static myValueType1()
19 {
20 Console.WriteLine("Hello from myValueType1");
21 // myInt = 111;
22 }
23 public static Int32 myInt;
24 }
25
26 struct myValueType2
27 {
28 static myValueType2()
29 {
30 Console.WriteLine("Hello from myValueType2");
31 }
32 public Int32 myInt;
33 }
34
35 struct myValueType3
36 {
37 static myValueType3()
38 {
39 Console.WriteLine("Hello from myValueType3");
40 myInt = 333;
41 }
42 public static Int32 myInt;
43 }
这里定义了三个结构:myValueType1,myValueType2,myValueType3。三个结构均带静态构造器,在构造器中都有一句用来输出的的代码。在myValueType1和myValueType3的静态。然后我们在main函数里面分别new 了相应的三个实例。您可以先想想输出的结果应该是怎样的。
事实上您会得到如下的结果:
我们看到虽然三个结构中都有静态构造器,却只有第一个结构的被执行了。事实上,这个有趣的现象也是CLR对性能的考虑,除非类型确实被访问到了,否则永远不会调用到它的类型构造器,这个过程是JIT的。
当执行到第六行代码时,CLR尝试要去myValueType1查找静态字段myInt的值。这个时候,myValueType1才是真正被访问到了。静态构造器被执行,得到相应的输出。
而myValueType2中myInt是个实例成员,访问它的值只关系到实例type2实例。与类型本身没有任何关系,CLR不会执行类型myValueType2的静态构造器。
myValueType3跟myValueType11几乎是一样的,myInt是静态成员,但是在main函数中,myValueType3还是没有被真正访问到,只是利用它构造出了一个虚拟的对象结构,这种对象结构里面所有字段都被赋予一个0值或者null值
所以第二行输出为零
这些性质与JIT编译器都是分不开的。