C#成員初始化有點(diǎn)坑爹
C#成員的初始化順序你真的非常清楚嗎,我發(fā)現(xiàn)有點(diǎn)坑爹,坑到爹突然有點(diǎn)搞不清楚什么狀況。下面咱們開始分析,先看3個(gè)簡(jiǎn)單類。
public abstract class Base { public Base() { SetValue(); } public abstract void SetValue(); } public class Sub : Base { public string value; public Sub() { value = "chentaihan"; } public override void SetValue() { value = "陳太漢"; } } public class Sub1 : Base { public string value = "chentaihan"; public override void SetValue() { value = "陳太漢"; } }
如果執(zhí)行下面這段代碼會(huì)輸出什么值呢,請(qǐng)不要往下看,先給出你自己的答案。
static class Program { static void Main(string[] args) { Sub sub = new Sub(); Console.WriteLine(sub.value); Sub1 sub1 = new Sub1(); Console.WriteLine(sub1.value); Console.Read(); } }
是的他很簡(jiǎn)單,但你確信你的答案就是對(duì)的嗎?這么一個(gè)簡(jiǎn)單的問題我答錯(cuò)了,所以就有了這篇博客。 CLR VIA C#這本書告訴我們:成員在定義的時(shí)候初始化相當(dāng)于在構(gòu)造函數(shù)的最上面初始化,如果一個(gè)成員在定義的時(shí)候初始化,并在構(gòu)造函數(shù)中賦值,那么在構(gòu)造函數(shù)執(zhí)行完成之后,該成員的值就是造函數(shù)中所賦的值,所以我得出的答案都是:chentaihan。但答案不是這樣的。當(dāng)運(yùn)行結(jié)果出來時(shí),我那個(gè)迷茫啊.....。
先來說說我的簡(jiǎn)單分析:
1:進(jìn)入子類構(gòu)造函數(shù)
2:Sub成員變量的內(nèi)存被分配
3:調(diào)用父類構(gòu)造函數(shù)
4:調(diào)用子類的方法SetValue(子類覆寫了這個(gè)方法),value被賦值
5:正式執(zhí)行子類構(gòu)造函數(shù),成員變量value再次被賦值
從上面5步我得出他們輸出的結(jié)果一樣,都是chentaihan。錯(cuò)在哪里呢?
于是我用Reflector查看了一下,得到的結(jié)果正如上面所說,他們的源碼是一樣的,如下所示。正如CLR VIA C#這本書說的那樣,那為什么結(jié)果不一樣呢,Reflector代碼是一樣的,執(zhí)行的結(jié)果卻不一樣,怎么回事,怎么回事,那我只能說Reflector坑爹,它不能反映程序的真正執(zhí)行邏輯,非要我用IL,我用的還不熟呢。
public class Sub : Base { public string value; public Sub() { value = "chentaihan"; } public override void SetValue() { value = "陳太漢"; } }
神馬情況,他們的IL代碼是不一樣的,如圖所示

看了這個(gè)圖,我們知道答案是chentaihan,陳太漢。誰能告訴我怎么調(diào)用父類的構(gòu)造函數(shù)和給value賦值的順序不一樣啊。該用的工具都用了,我該怎么證明這個(gè)結(jié)果,于是開始單步調(diào)試,于是發(fā)現(xiàn)了一個(gè)每天都發(fā)現(xiàn)了的秘密:成員初始化在構(gòu)造函數(shù)之前執(zhí)行。難怪這本書上說成員在定義的時(shí)候初始化相當(dāng)于在構(gòu)造函數(shù)的最上面初始化,Reflector也證實(shí)了這個(gè)答案。但是又繞進(jìn)另一個(gè)坑爹的問題:構(gòu)造函數(shù)還沒有調(diào)用,內(nèi)存還沒有分配,怎么給成員變量賦值啊?這不是問題,從上圖可以看出成員變量的賦值只是在父類的構(gòu)造函數(shù)之前調(diào)用,肯定也是在子類的成員變量分配空間之后為成員變量賦值。好的,最后我們得出的結(jié)論是:
1:進(jìn)入子類構(gòu)造函數(shù)
2:Sub成員變量的內(nèi)存被分配
3:為Sub成員變量賦值
4:調(diào)用父類構(gòu)造函數(shù)
5:調(diào)用子類的方法SetValue(子類覆寫了這個(gè)方法),value被賦值
6:正式執(zhí)行子類構(gòu)造函數(shù),成員變量value再次被賦值
同意以上觀點(diǎn)的人請(qǐng)放過我,別吐槽,不同意的請(qǐng)留言
這樣的解釋答案就很合理,但同時(shí)也說明成員變量在定義的時(shí)候初始化和在構(gòu)造函數(shù)中賦值的意義是不一樣的,至少執(zhí)行順序不一樣,產(chǎn)生的結(jié)果可能也不一樣。

作者:陳太漢
浙公網(wǎng)安備 33010602011771號(hào)