前言
.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 }