本文介紹 C# 6 的三個新語法:nameof 表示式、字串插值、和 null 條件運算子。
nameof 表示式
C# 6 新增的 nameof 關鍵字可用來取得某變數的名稱。請看底下這個簡單範例,便能了解其作用:
程式碼右邊的註解已經透露,nameof 是作用於編譯時期,而非執行時期。
那麼,它可以用在哪裡呢?
比如說,為了防錯,我們經常在函式中預先檢查參數值是否合法,並將不合法的參數透過拋異常(exception)的方式通知呼叫端(或者寫入 log 檔案以供將來診斷問題)。像這樣:
如此一來,當程式出錯時,用戶端就能輕易知道是哪個參數不對。問題是,程式中的參數名稱是寫死的字串值("productId"),將來萬一要修改參數名稱,稍不注意就會漏改這些字串。於是,即使煞費周章,仍有人選擇在執行時期動態取得參數名稱,只為了避免在程式中寫一堆固定的字串。其實,參數名稱在編譯時期就已經決定了,何不由編譯器代勞,既省事又不犧牲執行效率?
現在,C# 6 提供了 nameof 表示式,正好可以解決這個問題。於是剛才的範例可以改寫成這樣:
其中的 nameof(productId) 表示式在經過編譯之後,結果就等於手寫的固定字串 "productId"。
字串插值
.NET Framework 提供的字串格式化方法 String.Format(...) 是一種對號入座的寫法,相當好用。現在,C# 6 提供了另一種格式化字串的寫法,名曰「字串插值」(string interpolation)。
字串插值的基本語法,是在以雙引號包住的字串前面加上一個 '$' 字元,而在字串內容的部分使用一對大括弧 {} 來包住一個變數名稱。如下所示:
其中的「格式規範」就跟 String.Format() 方法所使用的格式規範字元一樣。一個格式字串裡面可以有多對大括弧,用來帶入不同的變數值,而沒有被大括弧包住的部分則維持不變。 參考底下的範例:
結果兩次輸出的字串值都相同,如下所示:
Michael Tsai 的月薪是 22,000
Michael Tsai 的月薪是 22,000
跟既有的 String.Format() 方法比較,我覺得字串插值的寫法更容易解讀,更容易想像最終格式化的結果。原因在於,解讀 String.Format() 時,我們必須把右邊的參數依序帶入左邊的格式字串;如果參數很多,有時還會對不上,導致順序錯置。新的字串插值語法則是直接在格式字串裡面填入變數名稱,不僅直觀,而且不會有弄錯順序的問題。
字串插值跟 nameof 表示式一樣都是語法糖,是編譯時期的魔法。明白地說,編譯器會把字串插值的語法編譯成 String.Format() 方法呼叫。底下是更多字串插值的範例,右邊註解則是編譯後的結果。
需特別注意的是,兩個連續的大括弧代表欲輸出一個大括弧字元。故第三個例子的執行結果為 "{測試大括弧}"。
Null 條件運算子
保險起見,在需要存取某物件的屬性之前,我們通常會先檢查該物件是否為 null,以免程式執行時拋出異常(NullReferenceException)。一般常見的寫法如下:
C# 6 新增了 null 條件運算子語法,讓你用更簡短的語法達到同樣效果:先判斷物件是否為 null,不是 null 才會存取其成員。它的寫法是在變數後面跟著一個問號,然後是存取成員名稱的表示式。參考以下範例:
更多範例:
小結
本文介紹的三種新語法當中,我會比較常用的應該是 nameof 和字串插值吧。
Happy coding!
摘自《C# 本事》(alpha 版)
nameof 表示式
C# 6 新增的 nameof 關鍵字可用來取得某變數的名稱。請看底下這個簡單範例,便能了解其作用:
string firstName = "Joey"; string varName = nameof(firstName); // 編譯結果:varName = "firstName"
程式碼右邊的註解已經透露,nameof 是作用於編譯時期,而非執行時期。
那麼,它可以用在哪裡呢?
比如說,為了防錯,我們經常在函式中預先檢查參數值是否合法,並將不合法的參數透過拋異常(exception)的方式通知呼叫端(或者寫入 log 檔案以供將來診斷問題)。像這樣:
void LoadProduct(string productId) { if (productId == null) { throw new ArgumentNullException("productId")); } .... }
如此一來,當程式出錯時,用戶端就能輕易知道是哪個參數不對。問題是,程式中的參數名稱是寫死的字串值("productId"),將來萬一要修改參數名稱,稍不注意就會漏改這些字串。於是,即使煞費周章,仍有人選擇在執行時期動態取得參數名稱,只為了避免在程式中寫一堆固定的字串。其實,參數名稱在編譯時期就已經決定了,何不由編譯器代勞,既省事又不犧牲執行效率?
現在,C# 6 提供了 nameof 表示式,正好可以解決這個問題。於是剛才的範例可以改寫成這樣:
void LoadProduct(string productId) { if (productId == null) { throw new ArgumentNullException(nameof(productId)); } .... }
其中的 nameof(productId) 表示式在經過編譯之後,結果就等於手寫的固定字串 "productId"。
字串插值
.NET Framework 提供的字串格式化方法 String.Format(...) 是一種對號入座的寫法,相當好用。現在,C# 6 提供了另一種格式化字串的寫法,名曰「字串插值」(string interpolation)。
字串插值的基本語法,是在以雙引號包住的字串前面加上一個 '$' 字元,而在字串內容的部分使用一對大括弧 {} 來包住一個變數名稱。如下所示:
$"{變數名稱:格式規範}"
其中的「格式規範」就跟 String.Format() 方法所使用的格式規範字元一樣。一個格式字串裡面可以有多對大括弧,用來帶入不同的變數值,而沒有被大括弧包住的部分則維持不變。 參考底下的範例:
string firstName = "Michael"; string lastName = "Tsai"; int salary = 22000; string msg1 = String.Format("{0} {1} 的月薪是 {2:C0}", firstName, lastName, salary); string msg2 = $"{firstName} {lastName} 的月薪是 {salary :C0}"; Console.WriteLine(msg1); Console.WriteLine(msg2);
結果兩次輸出的字串值都相同,如下所示:
Michael Tsai 的月薪是 22,000
Michael Tsai 的月薪是 22,000
跟既有的 String.Format() 方法比較,我覺得字串插值的寫法更容易解讀,更容易想像最終格式化的結果。原因在於,解讀 String.Format() 時,我們必須把右邊的參數依序帶入左邊的格式字串;如果參數很多,有時還會對不上,導致順序錯置。新的字串插值語法則是直接在格式字串裡面填入變數名稱,不僅直觀,而且不會有弄錯順序的問題。
字串插值跟 nameof 表示式一樣都是語法糖,是編譯時期的魔法。明白地說,編譯器會把字串插值的語法編譯成 String.Format() 方法呼叫。底下是更多字串插值的範例,右邊註解則是編譯後的結果。
$"姓名 = {myName}" // String.Format("姓名 = {0}", myName) $"小時 = {DateTime.Now:hh}" // String.Format("小時 = {0:hh}", DateTime.Now) $"{{測試大括弧}}" // String.Format("{{測試大括弧}}") $"{{秒 = {DateTime.Now :ss}}}" // String.Format("{{秒 = {0:mm}}}", DateTime.Now)
需特別注意的是,兩個連續的大括弧代表欲輸出一個大括弧字元。故第三個例子的執行結果為 "{測試大括弧}"。
Null 條件運算子
保險起見,在需要存取某物件的屬性之前,我們通常會先檢查該物件是否為 null,以免程式執行時拋出異常(NullReferenceException)。一般常見的寫法如下:
static void NullPropagationDemo(string s) { if (s != null && s.Length == 4) // 只有當 s 不為空時才存取它的 Length 屬性。 { // Do something. } }
C# 6 新增了 null 條件運算子語法,讓你用更簡短的語法達到同樣效果:先判斷物件是否為 null,不是 null 才會存取其成員。它的寫法是在變數後面跟著一個問號,然後是存取成員名稱的表示式。參考以下範例:
static void NullPropagationDemo(string s) { if (s?.Length == 4) // 只有當 s 不為空時才存取它的 Length 屬性。 { // Do something. } }
更多範例:
int? length = productList?.Length; // 若 productList 是 null,則 length 也是 null。 Customer obj = productList?[0]; // 若 productList 是 null,則 obj 也是 null。 int length = productList?.Length ?? 0; // 若 productList 是 null,則 length 是 0。 string name = productList?[0].FullName; // 若 productList 是 null,則 name 是 null。
小結
本文介紹的三種新語法當中,我會比較常用的應該是 nameof 和字串插值吧。
Happy coding!
摘自《C# 本事》(alpha 版)
沒有留言: