天天看點

30分鐘掌握 C#6

1. 隻讀自動屬性(Read-only auto-properties)

 C# 6之前我們建構隻讀自動屬性:

1   public string FirstName { get; private set; }
2   public string LastName { get; private set; }      

原了解析:就是編譯器在生成set通路器時,它的修飾符是private,由上可知所謂的隻讀隻是針對類外部,在類内部還是可以随意修改屬性值的。

 C# 6中提供了真正的隻讀自動屬性,寫法如下:

1   public string FirstName { get; }
2   public string LastName { get; }      

 原了解析:首先編譯器會生成一個readonly的私有字段而get通路器就是傳回該字段的值,由上可知該隻讀自動屬性隻能在構造函數中為其指派。

2. 自動屬性初始化器(Auto-Property Initializers)

 以前自動屬性的指派操作我們隻能寫在方法中,如構造函數:

1 public Student(string firstName, string lastName)
2 {
3     FirstName = firstName;
4     LastName = lastName;
5 }      

 但在C# 6中我們可以把指派操作當作聲明的一部份,如下所示:

1   public string FirstName { get; set; } = "Corleone";
2   public string LastName { get; set; } = "Mike";      

 備注:其實C# 6和之前的版本都一樣指派操作最終都是在方法中完成,但後者明顯更簡潔直覺,是以這是個不錯的文法糖。

3. 函數成員的表達式體(Expression-bodied function members)

 C# 6中提供的一個新文法:對于隻有一條語句的方法體可以簡寫成表達式。如下面兩種情況:

 1. 方法(Methods)

1   public Student Create() => new Student();      

 等同于:

1   public Student Create()
2   {
3       return new Student();
4   }      

 2. 隻讀屬性(read only properties)

1   public string FullName => string.Format("{0},{1}", FirstName, LastName);      
1   public string FullName
2   {
3       get
4       {
5           return string.Format("{0},{1}", FirstName, LastName);
6       }
7   }      

原了解析:上面的表達式在編譯後會生成最原始的方法體和通路器,值得一提的是函數表達式體跟Lambda是兩個相似但不相同的東西,函數的表

達式體隻能帶一句話且不能包含return關鍵字但Lambda 能帶語句塊和包含關鍵字。

4. 使用靜态(using static)

 C# 6中的一個新文法:使用類型的靜态成員時可以省略其類型,如下所示:

1   using static System.String;       // 先導入對應成員類型
2   public bool IsNull(string str) => IsNullOrEmpty(str);           
1   public bool IsNull(string str) => string.IsNullOrEmpty(str);      

總結:該文法糖的目的是使代碼變得更簡潔,但這個應該是區分使用場景的,如:數學計算(Math類)使用此文法糖的确能夠簡潔代碼提高可讀

性,但在某處如果導入過多的類型那麼不僅不能提高閱讀性反而會增加閱讀難度,因為你不知道這些成員具體屬于那個類型。還有若類型本身存在

同名成員使用時則會使用類型成員覆寫。

注意:使用靜态這一文法糖并不适用擴充方法,因為擴充方法的設計理念就是不修改已有代碼且隻能在一定範圍内使用,是以在特殊情況下需要将

其當作靜态方法來使用,那麼使用類名調用反而是比較明智的。

5. Null條件運算符(Null-conditional operators)

 稍有經驗的童鞋都知道在Coding過程中經常要判斷變量的值是否為null,類似這種if-else的操作還不少。這使得代碼看起來十分不簡潔,好在C#6

 中提供了解決方法:

1   var student = new Student();
2   var firstName = student?.FirstName;      

等同于:

1   var student = new Student();
2 
3   string firstName = null;
4   if (student != null)
5   {
6       firstName = student.FirstName;
7   }      

使用方法:隻需替換成員通路符 . 為 ?. ,若 ?. 左邊為null則整個運算符的結果也為null,否則運算符的結果就等于其成員值。假如成員的類型為值

類型則整個表達式傳回的類型是對應類型的可空類型,如:

1   int? age = student?.Age;      

 原了解析: ?. 編譯後就是 if 或 三元運算符,非指派操作(如:call)會編譯成 if,指派操作一般會編譯成三元運算符。

6. 字元串插值(String Interpolation)

 C# 6中提供了一種新文法來建構格式化字元串,如:

1   var fullName = $"{student.FirstName},{student.LastName}";      
1   var fullName = string.Format("{0},{1}", student.FirstName, student.LastName);      

 使用方法:隻需在字元串前加上$符号,然後在大括号中填寫表達式(字段、方法、Lambdad...)即可。

 備注:

 1. 字元串插值文法支援以前所有字元串格式設定(此項僅支援 .net framework,不支援 .net core 1.0.1),如:

1   Console.WriteLine($"平均成績:{student.GPA:F2}");      

 注:因為 : 總被編譯器解釋為表達式與字元串格式的分隔符,是以表達式中若有條件運算符則我們需要用括号來強制編譯将其解析成目前語境所要

 表達的意義。如:

1   Console.WriteLine($"平均成績:{(student.GPA > 80 ? student.GPA : 0):F2}");      

 2. 字元串插值文法可以嵌套,如:

1   var score = $"我的各科成績:{ $"數學:{student.MathScores};英語:{student.EnglishScore};"}";      

 原了解析:$"xxx{expression1}xxx{expression2}..." 編譯後就是string.Format()。

7. 異常過濾器(Exception Filters)

 C# 6中的一個新功能就是異常過濾器,它可以使我們在恰當的時機來應用Catch子句,如:

1   try
2   {
3       throw new WebException("Request timed out..", WebExceptionStatus.Timeout);
4   }
5   catch (WebException webEx) when (webEx.Status == WebExceptionStatus.Timeout)
6   {
7       // Exception handling
8   }      

 使用方法:try-catch() when()。

 總結:異常過濾器最大的亮點就是在使用恰當的情況下可以不丢失異常引發點的堆棧資訊,這對程式的排錯至關重要。另外它還有很多有意思的用

 法,大家可以上網查下。

8. nameof表達式(nameof Expressions)

 nameof 表達式的功能是擷取成員名稱,如抛異常:

1   public string FullName(Student student)
2   {
3       if (student == null)
4           throw new ArgumentNullException(nameof(student));
5 
6       return $"{student.FirstName},{student.LastName}";
7   }      

優點:nameof 表達式它能夠了解成員,當成員被重命名時nameof表達式中也重命名了,而常量字元串表示法是沒有這樣的優勢。

缺點:nameof 表達式生成的是不完全限定名,若你需要完全限定名 nameof 就不能幫你了。

原了解析:nameof 是編譯期間就确定其(成員)字元串名稱的,即編譯後就是常量字元串的表現形式了。

9. 在Catch和Finally中使用Await(Await in Catch and Finally blocks)

 C# 5 提供的 async 和 await 使異步程式設計變得極為簡便,但它們也有着局限性:await在catch和finally塊中不能使用。但這個問題已在C# 6中得到

 了解決,如:

1   public static async Task<string> MakeRequestAndLogFailures()
 2   {
 3       await logMethodEntrance();
 4       try
 5       {
 6           // ....
 7           var responseText = await streamTask;
 8           return responseText;
 9       }
10       catch (System.Net.Http.HttpRequestException e) when (e.Message.Contains("301"))
11       {
12           await logError("Recovered from redirect", e);
13           return "Site Moved";
14       }
15       finally
16       {
17           await logMethodExit();
18       }
19   }      

10. Index初始化器(Index Initializers)

 這個功能并沒有什麼新意,其實以前就支援集合/字典 初始化器了,如:

1   var list = new List<string>()
 2   {
 3       "Mike",
 4       "Jim"
 5   };
 6    
 7   var dic = new Dictionary<int, string>()
 8   {
 9       { 20, "Mike" },
10       { 30, "Jim"  }
11   };      

 在C# 6中隻是字典初始化器支援了新的寫法,如:

1   var dic = new Dictionary<int, string>()
2   {
3       [20] = "Mike",
4       [30] = "Jim"
5   };      

總結:暫無發現特殊的用法。

11. 改進的重載解析—編譯器(Improved overload resolution)

  這算不上是新文法,因為僅僅是編譯器的改進,之是以一提是想讓大家知道有這麼一回事。以前的編譯器是識别不了 Task.Run(Func<Task>())

  的,如下:

1   static Task DoThings()
2   {
3       return Task.FromResult(0);
4   }
5   
6   Task.Run(DoThings);  // 此處省略方法代碼...      

上述代碼在老版本編譯器下是編譯不通過的,而在新版本編譯器是能編譯通過的。

備注:值得一提的是新版本編譯器也隻是識别了Task.Run(Func<Task>()),Task.Run(Action) 還是識别不了,總的來說此功能對我們用處不大,

還不如乖乖的寫回Lambda表達式。

 由于篇幅所限,C# 7 新增的功能就放在下篇介紹......

如果您覺得閱讀本文對您有幫助,請點下:"推薦"。^_^

作者:VVStudyQQ群:469075305

出處:http://www.cnblogs.com/VVStudy/

本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接配接。