public class FirstExperience{ private string _stringAutoProp = "自動初始化屬性"; public string StringAutoProp { get{ return _stringAutoProp; } set{ _stringAutoProp = value; } }}
public class FirstExperience{ public string StringAutoProp { get; set; } = "自動初始化屬性";}
從反編譯中我們發現多了個私有字段this.<StringAutoProp>k__BackingField
;并在默認的構造函數中將“自動初始化屬性”賦值給了這個字段,那么可以推斷出IL中肯定會有這個匿名字段的定義,讓我們再來看看IL中的體現:
用上面的兩張圖我們可以得出以下結論
其實自動初始化屬性就是在CLR中體現就是創建私有的匿名字段,然后在構造函數中為這個匿名屬性賦值,而屬性的get
和Set
方法其實就是在操作這個匿名屬性。
public FirstExperience(int id){ _id = id;}private readonly int _id;public int ID{ get { return _id; }}
public int ReadonlyProp { get; }public FirstExperience(int _readonlyProp){ ReadonlyProp = _readonlyProp;}
從反編譯的結果我們看到構造函數中將傳進來的_readonlyProp
賦值給this.<ReadonlyProp>k__BackingField
字段,而屬性的get
方法操作的就是這個由編譯器生成的字段,而在ReadonlyProp
屬性的get
方法中打了CompilerGenerated
這個特性標簽,這個標簽其實就是區分編譯器生成的元素與用戶生成的元素,關于這個特性請移步到此。由此可以推斷IL中所做的操作與自動初始化屬性一致
public override string ToString(){ return string.Format("{0}",StringAutoProp);}
public override string ToString() => string.Format("{0}", StringAutoProp);
在6.0 語法中我們看到可以使用lambda表達式直接作為函數體,那么編譯器到底為我們做了什么呢?
從反編譯中我們可以看出編譯器編譯的時候把lambda
函數直接編譯成方法體,那么再看看IL的區別了。
從上面兩張圖中可以看出除了標注堆棧標注刻度
不同以外,看不出有什么差別。我也不是太明白這個地方,求園內的大牛解釋解釋!
if(xxx !=null){ xxx.ToString();}
這種寫法相信有非常多的朋友用過,經常為了一個是否為空的問題搞得代碼非常難看,
舉個栗子:我們需要獲取集合或者是字符喘的長度
if(parem!=null){ return parem.Length;}return null;
這樣的寫法實在太惡心了,在6.0語法中我們可以這么寫
public int? GetListCount(List<int> list){ return list?.Count();}
在實際應用中,經常會用到委托,而在之前我們需要調用委托時則需要判斷委托是否為空如下代碼:
public void Test(TestNew test){ if (test != null) { test.Invoke(); }}
對于強迫癥的我來說這樣太惡心了,于是乎利用6.0的語法開始改造
public void Test1(TestNew test){ test?.Invoke();}
從上圖反編譯效果可以看到兩個方法基本沒有差別,接下來看看IL中有什么差別:
上圖為6.0語法委托調用的IL圖,發現核心還是brtrue.s
做IF判斷決定執行流
public void MyMethod(string name){ if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException("name"); }}
上面代碼中的name
是我們手寫的字符串,在給參數name
改名時經常會忘記改下面的字符串name
,然而 6.0 解決了這個問題:
public void MyMethod(string name){ if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name)); }}
上圖中nameof(name)
被替換成了字符串name
,就如同常量一樣。繼續來看看IL做了什么:
從IL中我們可以看到它是直接ldstr
,既不是反射也不是拿變量的內存值,在實際運用中有時候我們會通過Type
來獲取他的類名或者是直接寫死的但是這樣通過反編譯后會發現Type.Name
在IL中其實是通過反射來獲取,而直接寫死的方式,在IL中其實就是定義一個變量到堆棧中然后再引用進去。
而nameof(name)
具有這兩種的的有點,靈活而且相對于type
和寫死的方式性能更高了。
其實6.0中還有很多新的語法糖,在這里就不一一介紹了,等不忙了,我在把其他的新的語法糖寫出來
非常感謝您花時間讀完這篇文章,如果您覺得此文不錯,請點一下“推薦”按鈕,您的“推薦”就是對我最大的鼓勵以及不懈努力的肯定。
本文版權歸作者和博客園所有,來源網址:http://www.49028c.com/Wesley-Zen/歡迎各位轉載,轉載文章之后必須在文章頁面明顯位置給出作者和原文連接,否則保留追究法律責任的權利以及小小的鄙視。
新聞熱點
疑難解答