天天看點

關于Type Initializer和 BeforeFieldInit的問題,看看大家能否給出正确的解釋

下面通過一個簡單的Console Application示範Type Innitializer的執行順序。希望大家各抒己見,對于實驗的結果給出一個圓滿的解釋,同時希望讀者從中了解到更多關于編譯、關于CLR一些被我們忽略的細節。

代碼如下,在類Foo中定義了兩個static成員:靜态字段Field和靜态方法GetString,Field通過于Inline的方式通過調用GetString進行初始化。在Main()中僅僅兩行代碼:Console.WriteLine("Start

...");Foo.GetString("Manually invoke the static GetString() method!"); 

對于結果,我想很多人都能夠猜得到,如果在顯示調用GetString()之前,需要完成靜态成員的初始化,是以最終的輸出結果如下圖所示:

<a target="_blank" href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/TypeInitializerBeforeFieldInit_DBE4/image_2.png"></a>

然後我們在Main()種多加一行代碼:string field = Foo.Field; 也就是擷取Foo的靜态字段:

<a target="_blank" href="http://11011.net/software/vspaste"></a>

最終的輸出結果就和上面不一樣了,靜态字段的初始化工作居然提前了(在Console.WriteLine("Start ...");之前執行)

<a target="_blank" href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/TypeInitializerBeforeFieldInit_DBE4/image_4.png"></a>

“神奇”的事情還沒有結束,如果我們在Foo中加上一個靜态構造函數,其中不執行任何的操作:

再來看看現在執行結果,又和先前的一樣的了。

我先不做任何評論(因為我也不太确定我的認識就是正确的),看看大家對此有什麼看法。

再添加另一個static

constructor的例子,較之上面一個要簡單點。在Bar繼承自基類Foo,在Foo和Bar均定義了靜态構造函數。靜态方法DoSomething()定義在Foo中,在Main()中卻通過Bar.DoSomething();進行調用。

下面是輸出結果,可見雖然通過Bar調用了靜态方法DoSomething,但是Bar的靜态構造函數沒有被執行。這個很好了解,因為Something是定義在基類Foo上,Bar.DoSomething()本質上相當于Foo.DoSomething()。是以隻會調用Foo的靜态構造函數。

<a target="_blank" href="http://images.cnblogs.com/cnblogs_com/artech/WindowsLiveWriter/TypeInitializerBeforeFieldInit_DBE4/image_8.png"></a>

個人覺得,這是編譯器值得改進的地方,既然靜态方法是基于類型的方法,隻能通過定義了該靜态方法的那個類型進行調用,至于其他的類,哪怕是該類的子類,都不能調用該方法。編譯器不應該讓這樣的代碼通過編譯。不知道讀者的意見如何。

作者:蔣金楠

微信公衆賬号:大内老A

如果你想及時得到個人撰寫文章以及著作的消息推送,或者想看看個人推薦的技術資料,可以掃描左邊二維碼(或者長按識别二維碼)關注個人公衆号(原來公衆帳号蔣金楠的自媒體将會停用)。

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接,否則保留追究法律責任的權利。

<a href="http://www.cnblogs.com/artech/archive/2008/11/01/1324280.html" target="_blank">原文連結</a>