前言
.NET4.0下是沒有Task.Run及Task.Delay方法的,而.NET4.5已經實現,對於還在使用.NET4.0的同學來說,如何在.NET4.0下實現這兩個方法呢?
在.NET4.0下,有一個泛型類,叫TaskCompletionSource<TReuslt>,它能控制Task的行為,如給Task設置結果、設置異常、設置取消等。
MSDN是這樣描述的(網址):
表示未綁定到委托的 Task<TResult> 的制造者方,並通過Task屬性提供對使用者方的訪問。
它有以下兩個常用方法:
1 public void SetException(Exception exception);
當執行的任務有異常時,可以使用該方法是設置任務的異常。
1 public void SetResult(TResult result);
這是給任務設置一個返回值,如果任務沒有返回值,直接設置null即可。
一、Task.Run(Action action)方法
該方法實現與Task.Factory.StartNew(Action action)類似,實現代碼如下:
1 public static Task Run(Action action) 2 { 3 var tcs = new TaskCompletionSource<object>(); 4 new Thread(() => { 5 try 6 { 7 action(); 8 tcs.SetResult(null); 9 } 10 catch (Exception ex) 11 { 12 tcs.SetException(ex); 13 } 14 }){ IsBackground = true }.Start(); 15 return tcs.Task; 16 }
該方法的目的是用來執行委托action所代表的方法,並返回當前所表示的任務,因方法的簽名返回值類型為Task,所以需給tcs的SetResult方法設置一個null值。
測試代碼如下:
1 TaskEx.Run(() => 2 { 3 Thread.Sleep(5000); 4 Console.WriteLine("Just For Test."); 5 });
該代碼的功能是在5s后輸出“Just For Test”字符串到控制台。
注:TaskEx是用來封裝Run靜態方法的一個類,以下內容相同。
二、Task.Run<TResult>(Func<TResult> function)方法
該方法是Task.Run(Action action)的泛型版本,實現如下:
1 public static Task<TResult> Run<TResult>(Func<TResult> function) 2 { 3 var tcs = new TaskCompletionSource<TResult>(); 4 new Thread(() => 5 { 6 try 7 { 8 tcs.SetResult(function()); 9 } 10 catch (Exception ex) 11 { 12 tcs.SetException(ex); 13 } 14 }) 15 { IsBackground = true }.Start(); 16 return tcs.Task; 17 }
與Task.Run的非泛型版本類似,該方法的目的是用來執行委托function所代表的方法,並返回當前所表示的任務,該任務類型為Task<TResut>,帶有Task的返回值。
測試代碼如下:
1 string result = TaskEx.Run(() => 2 { 3 Thread.Sleep(5000); 4 return "Just For Test."; 5 }).Result; 6 Console.WriteLine(result);
該方法的功能與上面的例子一樣:在5s后輸出“Just For Test”字符串到控制台,但其實現方式不一樣,一個用的是Action委托,另外一個使用的是Function<TResult>委托。
二、Task.Delay(int milliSeconds)方法
1 public static Task Delay(int milliseconds) 2 { 3 var tcs = new TaskCompletionSource<object>(); 4 var timer = new System.Timers.Timer(milliseconds) { AutoReset = false }; 5 timer.Elapsed += delegate { timer.Dispose();tcs.SetResult(null); }; 6 timer.Start(); 7 return tcs.Task; 8 }
以上代碼功能使用了System.Timers.Timer類來實現任務的延時,用來在milliSeconds毫秒后返回當前任務,該方法並不會阻塞人任何線程。
測試代碼如下:
1 TaskEx.Delay(5000).Wait(); 2 Console.WriteLine("Just For Test.");
該方法的功能還是與前面的兩個一樣,在5s后輸出“Just For Test”字符串到控制台。
完整代碼:
1 using System; 2 using System.Threading; 3 using System.Threading.Tasks; 4 5 namespace ConsoleApp 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 //Task.Run(Action action)方法 12 TaskEx.Run(() => 13 { 14 Thread.Sleep(5000); 15 Console.WriteLine("Just For Test."); 16 }); 17 18 //Task.Run<TResult>(Func<TResult> function)方法 19 string result = TaskEx.Run(() => 20 { 21 Thread.Sleep(5000); 22 return "Just For Test."; 23 }).Result; 24 Console.WriteLine(result); 25 26 //Task.Delay(int milliSeconds)方法 27 TaskEx.Delay(5000).Wait(); 28 Console.WriteLine("Just For Test."); 29 Console.ReadKey(); 30 } 31 } 32 class TaskEx 33 { 34 public static Task Run(Action action) 35 { 36 var tcs = new TaskCompletionSource<object>(); 37 new Thread(() => { 38 try 39 { 40 action(); 41 tcs.SetResult(null); 42 } 43 catch (Exception ex) 44 { 45 tcs.SetException(ex); 46 } 47 }){ IsBackground = true }.Start(); 48 return tcs.Task; 49 } 50 public static Task<TResult> Run<TResult>(Func<TResult> function) 51 { 52 var tcs = new TaskCompletionSource<TResult>(); 53 new Thread(() => 54 { 55 try 56 { 57 tcs.SetResult(function()); 58 } 59 catch (Exception ex) 60 { 61 tcs.SetException(ex); 62 } 63 }) 64 { IsBackground = true }.Start(); 65 return tcs.Task; 66 } 67 public static Task Delay(int milliseconds) 68 { 69 var tcs = new TaskCompletionSource<object>(); 70 var timer = new System.Timers.Timer(milliseconds) { AutoReset = false }; 71 timer.Elapsed += delegate { timer.Dispose();tcs.SetResult(null); }; 72 timer.Start(); 73 return tcs.Task; 74 } 75 } 76 }
