天天看點

C#成員初始化有點坑爹

C#成員的初始化順序你真的非常清楚嗎,我發現有點坑爹,坑到爹突然有點搞不清楚什麼狀況。下面咱們開始分析,先看3個簡單類。

<a></a>

如果執行下面這段代碼會輸出什麼值呢,請不要往下看,先給出你自己的答案。

是的他很簡單,但你确信你的答案就是對的嗎?這麼一個簡單的問題我答錯了,是以就有了這篇部落格。 CLR VIA C#這本書告訴我們:成員在定義的時候初始化相當于在構造函數的最上面初始化,如果一個成員在定義的時候初始化,并在構造函數中指派,那麼在構造函數執行完成之後,該成員的值就是造函數中所賦的值,是以我得出的答案都是:chentaihan。但答案不是這樣的。當運作結果出來時,我那個迷茫啊.....。

先來說說我的簡單分析:

1:進入子類構造函數

2:Sub成員變量的記憶體被配置設定

3:調用父類構造函數

4:調用子類的方法SetValue(子類覆寫了這個方法),value被指派

5:正式執行子類構造函數,成員變量value再次被指派

從上面5步我得出他們輸出的結果一樣,都是chentaihan。錯在哪裡呢?

于是我用Reflector檢視了一下,得到的結果正如上面所說,他們的源碼是一樣的,如下所示。正如CLR VIA C#這本書說的那樣,那為什麼結果不一樣呢,Reflector代碼是一樣的,執行的結果卻不一樣,怎麼回事,怎麼回事,那我隻能說Reflector坑爹,它不能反映程式的真正執行邏輯,非要我用IL,我用的還不熟呢。

神馬情況,他們的IL代碼是不一樣的,如圖所示

看了這個圖,我們知道答案是chentaihan,陳太漢。誰能告訴我怎麼調用父類的構造函數和給value指派的順序不一樣啊。該用的工具都用了,我該怎麼證明這個結果,于是開始單步調試,于是發現了一個每天都發現了的秘密:成員初始化在構造函數之前執行。難怪這本書上說成員在定義的時候初始化相當于在構造函數的最上面初始化,Reflector也證明了這個答案。但是又繞進另一個坑爹的問題:構造函數還沒有調用,記憶體還沒有配置設定,怎麼給成員變量指派啊?這不是問題,從上圖可以看出成員變量的指派隻是在父類的構造函數之前調用,肯定也是在子類的成員變量配置設定空間之後為成員變量指派。好的,最後我們得出的結論是: 

3:為Sub成員變量指派

4:調用父類構造函數

5:調用子類的方法SetValue(子類覆寫了這個方法),value被指派

6:正式執行子類構造函數,成員變量value再次被指派

同意以上觀點的人請放過我,别吐槽,不同意的請留言

這樣的解釋答案就很合理,但同時也說明成員變量在定義的時候初始化和在構造函數中指派的意義是不一樣的,至少執行順序不一樣,産生的結果可能也不一樣。

本文轉自啊漢部落格園部落格,原文連結:http://www.cnblogs.com/hlxs/archive/2012/04/19/2456949.html