天了噜!定义static字段还有顺序要求?
前言
前段時(shí)間,發(fā)現(xiàn)一個(gè)bug,代碼結(jié)構(gòu)類似下面的示例。你能說(shuō)出這段代碼的正確返回結(jié)果嗎?
class?Program {private?static?int?a1?=?a2;private?static?int?a2?=?Init();private?static?int?Init(){return?123;}static?void?Main(string[]?args){Console.WriteLine($@"{a1}?{a2}");} }答案是0 123!
如果改成這樣則返回123 123:
private?static?int?a2?=?Init(); private?static?int?a1?=?a2;定義static字段還有順序要求?
微軟官方文檔[1]明明是這樣說(shuō)的:
在首次訪問(wèn)靜態(tài)成員之前以及在調(diào)用構(gòu)造函數(shù)(如果有)之前,會(huì)初始化靜態(tài)成員。
不是應(yīng)該a2被訪問(wèn)之前會(huì)初始化嗎?
原因
通過(guò)C#代碼看不出問(wèn)題,我們看看IL代碼[2]實(shí)現(xiàn):
ldsfld 將靜態(tài)字段的值推送到計(jì)算堆棧上
stsfld 用來(lái)自計(jì)算堆棧的值替換靜態(tài)字段的值
原來(lái),靜態(tài)字段的初始化,是在所在類的靜態(tài)構(gòu)造函數(shù)中,按照定義的順序依次完成的。
由于a1和a2是在同一個(gè)類里定義的,為a1賦值時(shí)a2還沒(méi)有值,所以使用的是int類型默認(rèn)值。
解決方法
為了避免這個(gè)問(wèn)題,最好不使用同一個(gè)類里的靜態(tài)字段用于初始化,類似這樣:
private?static?int?a1?=?OtherClass.a2;如果就是要這樣用,可以改成這樣的寫法:
private?static?int?b1?=?b2; private?static?int?b2?=>?Init();通過(guò)IL代碼可以看到:
b2被轉(zhuǎn)換成get屬性,因此不用初始化。
結(jié)論
細(xì)節(jié)是魔鬼!原來(lái)定義static字段還真有順序要求!
如果你覺(jué)得這篇文章對(duì)你有所啟發(fā),請(qǐng)關(guān)注我的個(gè)人公眾號(hào)”My IO“,記住我!
參考資料
[1]
微軟官方文檔: https://docs.microsoft.com/zh-cn/dotnet/csharp/programming-guide/classes-and-structs/static-classes-and-static-class-members#static-members
[2]IL代碼: C#源代碼會(huì)被編譯為IL代碼,運(yùn)行時(shí)將IL轉(zhuǎn)為機(jī)器能識(shí)別的機(jī)器碼
總結(jié)
以上是生活随笔為你收集整理的天了噜!定义static字段还有顺序要求?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 使用 dotnet-monitor 在
- 下一篇: 所以,路遥工具箱到底是什么东西?