前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于Type Initializer和 BeforeFieldInit的问题,看看大家能否给出正确的解释

关于Type Initializer和 BeforeFieldInit的问题,看看大家能否给出正确的解释

作者头像
蒋金楠
发布2022-05-09 13:03:39
1940
发布2022-05-09 13:03:39
举报
文章被收录于专栏:大内老A

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

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

代码语言:javascript
复制
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()之前,需要完成静态成员的初始化,所以最终的输出结果如下图所示:

image
image

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

代码语言:javascript
复制
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 ...");之前执行)

image
image

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

代码语言:javascript
复制
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: }

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

image
image

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

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

代码语言:javascript
复制
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的静态构造函数。

image
image

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

作者:Artech 出处:http://artech.cnblogs.com 本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2008-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档