天了噜!定义static字段还有顺序要求?
前言
前段時間,發現一個bug,代碼結構類似下面的示例。你能說出這段代碼的正確返回結果嗎?
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]明明是這樣說的:
在首次訪問靜態成員之前以及在調用構造函數(如果有)之前,會初始化靜態成員。
不是應該a2被訪問之前會初始化嗎?
原因
通過C#代碼看不出問題,我們看看IL代碼[2]實現:
ldsfld 將靜態字段的值推送到計算堆棧上
stsfld 用來自計算堆棧的值替換靜態字段的值
原來,靜態字段的初始化,是在所在類的靜態構造函數中,按照定義的順序依次完成的。
由于a1和a2是在同一個類里定義的,為a1賦值時a2還沒有值,所以使用的是int類型默認值。
解決方法
為了避免這個問題,最好不使用同一個類里的靜態字段用于初始化,類似這樣:
private?static?int?a1?=?OtherClass.a2;如果就是要這樣用,可以改成這樣的寫法:
private?static?int?b1?=?b2; private?static?int?b2?=>?Init();通過IL代碼可以看到:
b2被轉換成get屬性,因此不用初始化。
結論
細節是魔鬼!原來定義static字段還真有順序要求!
如果你覺得這篇文章對你有所啟發,請關注我的個人公眾號”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#源代碼會被編譯為IL代碼,運行時將IL轉為機器能識別的機器碼
總結
以上是生活随笔為你收集整理的天了噜!定义static字段还有顺序要求?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用 dotnet-monitor 在
- 下一篇: 所以,路遥工具箱到底是什么东西?