博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于Type Initializer和 BeforeFieldInit的问题,看看大家能否给出正确的解释
阅读量:7070 次
发布时间:2019-06-28

本文共 2852 字,大约阅读时间需要 9 分钟。

下面通过一个简单的Console Application演示Type Innitializer的执行顺序。希望大家各抒己见,对于实验的结果给出一个圆满的解释,同时希望读者从中理解到更多关于编译、关于CLR一些被我们忽略的细节。

代码如下,在类Foo中定义了两个static成员:静态字段Field和静态方法GetString,Field通过于Inline的方式通过调用GetString进行初始化。在Main()中仅仅两行代码:Console.WriteLine("Start ...");Foo.GetString("Manually invoke the static GetString() method!"); 

1: using System;
2: namespace Artech.TypeInitializerDemo
3: {
4:     class Program
5:     {
6:         static void Main()
7:         {
8:             Console.WriteLine("Start ...");
9:             Foo.GetString("Manually invoke the static GetString() method!");
10:         }
11:     }
12: 
13:     class Foo
14:     {
15:         public static string Field = GetString("Initialize the static field!");
16: 
17:         public static string GetString(string s)
18:         {
19:             Console.WriteLine(s);
20:             return s;
21:         }
22:     }
23: }

对于结果,我想很多人都能够猜得到,如果在显示调用GetString()之前,需要完成静态成员的初始化,所以最终的输出结果如下图所示:

然后我们在Main()种多加一行代码:string field = Foo.Field; 也就是获取Foo的静态字段:

1: static void Main()
2: {
3:     Console.WriteLine("Start ...");
4:     Foo.GetString("Manually invoke the static GetString() method!");
5:     string field = Foo.Field;
6: }

最终的输出结果就和上面不一样了,静态字段的初始化工作居然提前了(在Console.WriteLine("Start ...");之前执行)

“神奇”的事情还没有结束,如果我们在Foo中加上一个静态构造函数,其中不执行任何的操作:

1: class Foo
2: {
3:     public static string Field = GetString("Initialize the static field!");
4: 
5:     static Foo()
6:     { }
7: 
8:     public static string GetString(string s)
9:     {
10:         Console.WriteLine(s);
11:         return s;
12:     }
13: }

再来看看现在执行结果,又和先前的一样的了。

 

我先不做任何评论(因为我也不太确定我的认识就是正确的),看看大家对此有什么看法。

再添加另一个static constructor的例子,较之上面一个要简单点。在Bar继承自基类Foo,在Foo和Bar均定义了静态构造函数。静态方法DoSomething()定义在Foo中,在Main()中却通过Bar.DoSomething();进行调用。

1: using System;
2: namespace Artech.TypeInitializerDemo
3: {
4:     class Program
5:     {
6:         static void Main()
7:         {
8:             Bar.DoSomething();
9:         }
10:     }
11: 
12:     public abstract class Foo
13:     {
14:         static Foo()
15:         {
16:             Console.WriteLine("static Foo() is invoked");
17:         }
18: 
19:         public static void DoSomething()
20:         {
21:             Console.WriteLine("Done ...");
22:         }
23:     }
24: 
25:     public class Bar : Foo
26:     {
27:         static Bar()
28:         {
29:             Console.WriteLine("static Bar() is invoked");
30:         }
31:     }
32: }

下面是输出结果,可见虽然通过Bar调用了静态方法DoSomething,但是Bar的静态构造函数没有被执行。这个很好理解,因为Something是定义在基类Foo上,Bar.DoSomething()本质上相当于Foo.DoSomething()。所以只会调用Foo的静态构造函数。

个人觉得,这是编译器值得改进的地方,既然静态方法是基于类型的方法,只能通过定义了该静态方法的那个类型进行调用,至于其他的类,哪怕是该类的子类,都不能调用该方法。编译器不应该让这样的代码通过编译。不知道读者的意见如何。


作者:蒋金楠
微信公众账号:大内老A
微博:
如果你想及时得到个人撰写文章以及著作的消息推送,或者想看看个人推荐的技术资料,可以扫描左边二维码(或者长按识别二维码)关注个人公众号(原来公众帐号
蒋金楠的自媒体将会停用)。
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
你可能感兴趣的文章
iOS-网络爬虫
查看>>
jira
查看>>
elasticsearch rpm 安装
查看>>
Python基础总结(字符串常用,数字类型转换,基本运算符与流程控制)
查看>>
数据预处理——剔除异常值,平滑,归一化
查看>>
Visual stuido 项目路径的奇怪问题
查看>>
java局部变量和临时变量
查看>>
返回杨辉三角前 n 层的数字
查看>>
布局(2、相对布局)
查看>>
在 Eclipse 上配置tomcat7.0并创建工程发布
查看>>
腾讯移动分析 签名代码示例
查看>>
重新回归博客园,写在开始的话。
查看>>
JavaScript定义函数
查看>>
AJAX的基础
查看>>
安全使用电子邮件十三法
查看>>
开发人员必知的20+HTML5技巧
查看>>
组合数学
查看>>
Loadrunner如何添加负载机
查看>>
Vue中组件之间的通信方式
查看>>
数据库并行读取和写入(Python实现)
查看>>