標籤:sharp 方式 語言特性 final lte header otn delegate log
0. 目錄
C#6 新增特性目錄
1. 在catch和finally塊中使用await
在C#5中引入一對關鍵字await/async,用來支援新的非同步編程模型,使的C#的非同步編程模型進一步的簡化(APM->EAP->TAP->await/async,關於C#中的非同步編程模型的不是本篇文章的介紹重點,詳細的資料請移步這裡Asynchronous Programming Pattern)。在C#5中雖然引入了await/async,但是卻有一些限制,比如不能再catch和finally語句塊中使用,C#6中將不再受此限制。
1 using System; 2 using System.Threading; 3 using System.Threading.Tasks; 4 5 namespace csharp6 6 { 7 internal class Program 8 { 9 private static void Main(string[] args)10 {11 do12 {13 Log(ConsoleColor.White, "caller method begin", true);14 CallerMethod();15 Log(ConsoleColor.White, "caller method end");16 } while (Console.ReadKey().Key != ConsoleKey.Q);17 }18 19 public static async void CallerMethod()20 {21 try22 {23 Log(ConsoleColor.Yellow, "try ", true);24 throw new Exception();25 }26 catch (Exception)27 {28 Log(ConsoleColor.Red, "catch await begin", true);29 await AsyncMethod();30 Log(ConsoleColor.Red, "catch await end");31 }32 finally33 {34 Log(ConsoleColor.Blue, "finally await begin", true);35 await AsyncMethod();36 Log(ConsoleColor.Blue, "finally await end");37 }38 }39 40 private static Task AsyncMethod()41 {42 return Task.Factory.StartNew(() =>43 {44 Log(ConsoleColor.Green, "async method begin");45 Thread.Sleep(1000);46 Log(ConsoleColor.Green, "async method end");47 });48 }49 50 private static void Log(ConsoleColor color, string message, bool newLine = false)51 {52 if (newLine)53 {54 Console.WriteLine();55 }56 Console.ForegroundColor = color;57 Console.WriteLine($"{message,-20} : {Thread.CurrentThread.ManagedThreadId}");58 }59 }60 }
運行結果如下:
如果你細心的話會發現async method begin:6這一行的顏色居然不是我設定的綠色,而是白色,而且順序也出現了錯亂;而你再運行一次,它可能就是綠色了。這其實是由於我在Log方法(非安全執行緒的方法)裡面的兩行代碼被多個線程爭搶調用引起的:
1 Console.ForegroundColor = color;2 Console.WriteLine($"{message,-20} : {Thread.CurrentThread.ManagedThreadId}");
我們可以做點小改動來讓Log方法做到安全執行緒(在C#中有很多方式可以做到,這隻是其中一種):
1 [MethodImpl(MethodImplOptions.Synchronized)] 2 private static void Log(ConsoleColor color, string message, bool newLine = false) 3 { 4 if (newLine) 5 { 6 Console.WriteLine(); 7 } 8 Console.ForegroundColor = color; 9 Console.WriteLine($"{message,-20} : {Thread.CurrentThread.ManagedThreadId}");10 }
貌似有點跑題了,迴歸正題,在catch和finally語句塊中支援await關鍵字並不需要IL指令的支援,也不需要CLR的支援,而僅僅是編譯器做出的代碼轉換(await/async就像lambda一樣到delegate一樣)。具體的IL就不做展開了,太龐大了,貼個圖看下大致的情況:
我們在CallerMethod中所寫的代碼,被轉移到MoveNext中(更詳細的資料請移步園友"Dev_Eric"的一篇部落格:進階篇:以IL為劍,直指async/await)(包括catch和finally中的await語句)。
2. 異常過濾器
其實這個語言特性在VB,F#裡面早就支援了,現在C#6裡面也可以使用了。
1 try { … }2 catch (Exception e) when (filter(e))3 {4 …5 }
其中when這一塊就是異常過濾器生效的地方,when後面跟一個運算式,運算式結果如果為true,則進入當前catch語句塊。
3. 參考
Asynchronous Programming Patterns
C# 6.0 await in catch/finally
C# 6.0 Exception filters
http://www.sadev.co.za/content/exception-filtering-c-6
[C#6] 8-異常增強