.Net4.0如何实现.NET4.5中的Task.Run及Task.Delay方法

时间:2023-03-08 22:34:01

前言

.NET4.0下是没有Task.Run及Task.Delay方法的,而.NET4.5已经实现,对于还在使用.NET4.0的同学来说,如何在.NET4.0下实现这两个方法呢?

在.NET4.0下,有一个泛型类,叫TaskCompletionSource<TReuslt>,它能控制Task的行为,如给Task设置结果、设置异常、设置取消等。

MSDN是这样描述的(网址):

表示未绑定到委托的 Task<TResult> 的制造者方,并通过Task属性提供对使用者方的访问。

它有以下两个常用方法:

 public void SetException(Exception exception);

当执行的任务有异常时,可以使用该方法是设置任务的异常。

 public void SetResult(TResult result);

这是给任务设置一个返回值,如果任务没有返回值,直接设置null即可。

一、Task.Run(Action action)方法

该方法实现与Task.Factory.StartNew(Action action)类似,实现代码如下:

         public static Task Run(Action action)
{
var tcs = new TaskCompletionSource<object>();
new Thread(() => {
try
{
action();
tcs.SetResult(null);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}){ IsBackground = true }.Start();
return tcs.Task;
}

该方法的目的是用来执行委托action所代表的方法,并返回当前所表示的任务,因方法的签名返回值类型为Task,所以需给tcs的SetResult方法设置一个null值。

测试代码如下:

             TaskEx.Run(() =>
{
Thread.Sleep();
Console.WriteLine("Just For Test.");
});

该代码的功能是在5s后输出“Just For Test”字符串到控制台。

注:TaskEx是用来封装Run静态方法的一个类,以下内容相同。

二、Task.Run<TResult>(Func<TResult> function)方法

该方法是Task.Run(Action action)的泛型版本,实现如下:

         public static Task<TResult> Run<TResult>(Func<TResult> function)
{
var tcs = new TaskCompletionSource<TResult>();
new Thread(() =>
{
try
{
tcs.SetResult(function());
}
catch (Exception ex)
{
tcs.SetException(ex);
}
})
{ IsBackground = true }.Start();
return tcs.Task;
}

与Task.Run的非泛型版本类似,该方法的目的是用来执行委托function所代表的方法,并返回当前所表示的任务,该任务类型为Task<TResut>,带有Task的返回值。

测试代码如下:

             string result = TaskEx.Run(() =>
{
Thread.Sleep();
return "Just For Test.";
}).Result;
Console.WriteLine(result);

该方法的功能与上面的例子一样:在5s后输出“Just For Test”字符串到控制台,但其实现方式不一样,一个用的是Action委托,另外一个使用的是Function<TResult>委托。

二、Task.Delay(int milliSeconds)方法

         public static Task Delay(int milliseconds)
{
var tcs = new TaskCompletionSource<object>();
var timer = new System.Timers.Timer(milliseconds) { AutoReset = false };
timer.Elapsed += delegate { timer.Dispose();tcs.SetResult(null); };
timer.Start();
return tcs.Task;
}

以上代码功能使用了System.Timers.Timer类来实现任务的延时,用来在milliSeconds毫秒后返回当前任务,该方法并不会阻塞人任何线程。

测试代码如下:

             TaskEx.Delay().Wait();
Console.WriteLine("Just For Test.");

该方法的功能还是与前面的两个一样,在5s后输出“Just For Test”字符串到控制台。

完整代码:

 using System;
using System.Threading;
using System.Threading.Tasks; namespace ConsoleApp
{
class Program
{
static void Main(string[] args)
{
//Task.Run(Action action)方法
TaskEx.Run(() =>
{
Thread.Sleep();
Console.WriteLine("Just For Test.");
}); //Task.Run<TResult>(Func<TResult> function)方法
string result = TaskEx.Run(() =>
{
Thread.Sleep();
return "Just For Test.";
}).Result;
Console.WriteLine(result); //Task.Delay(int milliSeconds)方法
TaskEx.Delay().Wait();
Console.WriteLine("Just For Test.");
Console.ReadKey();
}
}
class TaskEx
{
public static Task Run(Action action)
{
var tcs = new TaskCompletionSource<object>();
new Thread(() => {
try
{
action();
tcs.SetResult(null);
}
catch (Exception ex)
{
tcs.SetException(ex);
}
}){ IsBackground = true }.Start();
return tcs.Task;
}
public static Task<TResult> Run<TResult>(Func<TResult> function)
{
var tcs = new TaskCompletionSource<TResult>();
new Thread(() =>
{
try
{
tcs.SetResult(function());
}
catch (Exception ex)
{
tcs.SetException(ex);
}
})
{ IsBackground = true }.Start();
return tcs.Task;
}
public static Task Delay(int milliseconds)
{
var tcs = new TaskCompletionSource<object>();
var timer = new System.Timers.Timer(milliseconds) { AutoReset = false };
timer.Elapsed += delegate { timer.Dispose();tcs.SetResult(null); };
timer.Start();
return tcs.Task;
}
}
}