看看C# 6.0中那些語法糖都幹了些什麼(終結篇)

一線碼農發表於2014-12-23

  終於寫到終結篇了,整個人像在夢遊一樣,說完這一篇我得繼續寫我的js系列啦。

 

一:帶索引的物件初始化器

  還是按照江湖老規矩,先扒開看看到底是個什麼玩意。

1         static void Main(string[] args)
2         {
3             Dictionary<string, string> dic = new Dictionary<string, string>()
4             {
5                 ["Name"] = "ctrip",
6                 ["Age"] = "15"
7             };
8         }

第一眼看到這個還是蠻新鮮的,不過轉眼就能想到是不是跟陣列初始化器,物件初始化器一個樣?你要是這麼想就對了,下面我們來看看這玩意會生成

什麼樣的IL。

 

 

從上圖中可以清楚的看到set_Item方法,這個方法就是編譯器上層的索引器語法糖,就是忽悠我們提高開發效率的,不過也還行,起碼讓我少輸入了

兩個dic,然後把程式碼還原如下:

1             Dictionary<string, string> dic = new Dictionary<string, string>();
2             dic["Name"] = "ctrip";
3             dic["Age"] = "20";

 

索性趁熱打鐵,看看這個索引器方法的內部程式碼是什麼樣的,從下圖中可以看到是一個Insert操作。

 

二:無引數的結構體建構函式

  不知道有多少人知道值型別在C#6.0之前是絕對不可以定義預設建構函式的,為什麼這麼說呢?道理很簡單,因為值型別和引用型別的機制不一樣,

值型別不需要new就可以在棧中分配空間,比如下面的結構體Point,只要我們定義了,就可以方便的使用point.X值。

 

那問題來了,如果我定義了一個預設的建構函式,並且在裡面寫下x=5,y=5,那誰可以告訴我,當我定義point的時候,有沒有呼叫建構函式呢???

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Console;
 7 
 8 namespace ConsoleApplication3
 9 {
10     class Program
11     {
12         static void Main(string[] args)
13         {
14             Test t = new Test();
15             var s = t.point.X;    //請問有沒有呼叫建構函式啊?啊啊啊啊啊。。。。。。。。。。。。。。。
16             Console.Read();
17         }
18     }
19 
20     public class Test
21     {
22         public Point point;
23     }
24 
25     public struct Point
26     {
27         public int X;
28 
29         public int Y;
30 
31         public Point()
32         {
33             X = 5;
34             Y = 5;
35         }
36     }
37 }

如果執行了預設建構函式,那我point.X的時候會輸出5,是不是覺得有點奇怪呢?所以基於這個原因,C#6.0之前為了避嫌,就禁止了這種預設的值

型別構造形式。但是這次在C#6.0中居然放開了,所以我就很迫不及待的去看一看到底調沒呼叫預設建構函式,如下圖:

 

 

從圖中看到並沒有呼叫預設建構函式,到這裡我也知道了,只有在我new的時候才會呼叫,所以我就發現,值型別是在模仿引用型別的使用方式了,

個人感覺真的沒有必要放開這個限制。

 

 

三:異常篩選器

  C#6.0中這個異常篩選器還真是個比較新奇的東西,不看不知道,一看嚇一跳,比如下面的程式碼。

 1         public void Run()
 2         {
 3             try
 4             {
 5             }
 6             catch (Exception ex)
 7             if (ex.Message.Contains("timeout"))
 8             {
 9                 throw;
10             }
11         }

 

如果你仔細看的話,好像就是一個catch中省略了{}而已嘛?並沒有看到什麼其他特殊的東西,然後我就非常好奇的把上面的程式碼恢復到6.0版本之前,

程式碼如下:

 1         public void Run1()
 2         {
 3             try
 4             {
 5 
 6             }
 7             catch (Exception ex)
 8             {
 9                 if (ex.Message.Contains("timeout"))
10                 {
11                     throw;
12                 }
13             }
14         }

接來下,我們就來看看這兩份程式碼的IL到底會是個什麼樣子?內心狂雞凍啊,啊啊啊啊啊啊啊。。。。都痙攣了。。。。。

 

可以看到,上面兩份貌似相同的程式碼,其實生成的IL還是有很大區別的,新版程式碼中會用isinst判斷是否為Exception的例項,並且用brtrue來判斷當前是否

為null,如果是null,則不會執行ex.Message.Contains("timeout")語句了。但是老版程式碼並沒有true/false判斷,還是按照常規執行,所以現在可以知道,

其實並不是簡單的省略了個"{}"大括號,這個語法糖在底層還是有些智慧判斷的。

 

好了,所有的C#6.0的語法糖分析到這裡就結束了,感謝大家的關注。

 

相關文章