编译器对私有字段初始化的优化
今天Review時看到自己寫的這樣一段類似的代碼:
internal class TestClass {private bool _inited = false;private int _count = 0; }簡單地說就是一個類中的私有字段被顯示地賦上了默認值。根據我們慣有的經驗,這么做不僅多此一舉,而且畫蛇添足。因為false和0分別是bool型和int型的默認值,也即是如果我們沒有顯示賦值,它們仍然會是false和0.那么這樣其實會在執行時多走一步,是丑陋的代碼。
?
果真如此嗎?
?
事實上,在某些情況下,上面的代碼確實會多執行一次,也即CLR在給所有的字段賦上默認值后,我們的邏輯又會把這些字段賦一遍默認值,而且這個賦值的過程是在構造函數中完成的。但是這個情況有一個大大的前提:Debug模式。
?
查看Debug模式下編譯的TestClass的構造器IL指令,可以看到這里確實生成了為字段賦默認值的指令,部分證實了我們的猜想。
?
那么相同的代碼打開Release模式再編譯一遍,再來看看結果有什么不一樣的吧。
?
讓我們欣慰的是,C#編譯器已經聰明地識別出了這是一段完全多余的代碼,并且幫助我們做了優化,在構造函數中并不會對賦了默認值的私有字段做任何操作。在任何情況下,我們發布出去的dll都應該是經過Release編譯的,所以之前的擔心是完全沒有必要的。而且鑒于這么做并沒有任何性能的損失,顯示地給字段賦初值會讓閱讀者更容易理解作者的用途,不至于迷惑于“是開發忘記了賦初值還是他確實想這么做?”。
?
明白了這一點之后我們再來看一個更進一步的:
internal class TestClass {public TestClass(){_inited = false;_count = 0;}private bool _inited;private int _count; }這樣一段代碼,同樣在Release模式下編譯。都說直接給字段賦值只是通過構造器賦值的一個語法糖,那么上述代碼會否被優化呢?編譯器有如此聰明么??很遺憾,看來果然不如我們想象地那般神奇。而且和第一張IL代碼圖進行比較會發現兩個構造器對私有字段初始化的時間點是不一樣的,直接賦值的初始化點在調用父類的構造器之前,而在構造器中賦值的初始化點在調用父類的構造器之后。通過這里我們可以大致猜出一個實例的構造順序,即是先有字段,再調用父類構造器,再調用自身構造器。可以通過如下代碼做個簡單的驗證:
internal class TestClass {public TestClass(){_inited = false;_count = 0;}private bool _inited = true;private int _count = 1; }我們并沒有給字段賦上默認值,這樣可以強迫編譯器生成這一段IL指令。查看它的Release編譯的IL指令:??
結果證明了我們的猜想,其中紅圈賦值1的操作是我們直接賦值的IL代碼,在調用Object的構造器之前執行。而藍色方框標出的賦值0的操作是我們構造器中顯示賦值的IL代碼,在調用Object的構造器之后。
轉載于:https://www.cnblogs.com/Tyr-Tian/archive/2011/05/04/2037114.html
《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的编译器对私有字段初始化的优化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python之中文识别
- 下一篇: c++自定义的数据库类