.NET 4.0中如何实现与.NET 4.5中的Task.Delay相同的效果?
TaskEx.Delay
函数。你可以使用 Timer
在4.0中创建一个 Delay
方法:
public static Task Delay(double milliseconds)
{
var tcs = new TaskCompletionSource<bool>();
System.Timers.Timer timer = new System.Timers.Timer();
timer.Elapsed+=(obj, args) =>
{
tcs.TrySetResult(true);
};
timer.Interval = milliseconds;
timer.AutoReset = false;
timer.Start();
return tcs.Task;
}
TrySetResult
永远不会被调用。 - Edward BreyTimer
类在内部专门处理这个问题,以确保使用它的用户不需要在其生命周期中持有对它的引用。只要计时器正在运行,它就会从根位置添加对自身的引用,然后在不再运行时将其删除。 - Servyusing System;
using System.Threading;
using System.Threading.Tasks;
class Program
{
static void Main()
{
Delay(2000).ContinueWith(_ => Console.WriteLine("Done"));
Console.Read();
}
static Task Delay(int milliseconds)
{
var tcs = new TaskCompletionSource<object>();
new Timer(_ => tcs.SetResult(null)).Change(milliseconds, -1);
return tcs.Task;
}
}
object
,用于打印其ToString
方法的值。请注意,他在实际实现中没有使用该方法或任何其他非库方法,只是测试它的示例函数。 - ServyDelay
方法感兴趣。using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DelayImplementation
{
class Program
{
static void Main(string[] args)
{
System.Threading.CancellationTokenSource tcs = new System.Threading.CancellationTokenSource();
int id = 1;
Console.WriteLine(string.Format("Starting new delay task {0}. This one will be cancelled.", id));
Task delayTask = Delay(8000, tcs.Token);
HandleTask(delayTask, id);
System.Threading.Thread.Sleep(2000);
tcs.Cancel();
id = 2;
System.Threading.CancellationTokenSource tcs2 = new System.Threading.CancellationTokenSource();
Console.WriteLine(string.Format("Starting delay task {0}. This one will NOT be cancelled.", id));
var delayTask2 = Delay(4000, tcs2.Token);
HandleTask(delayTask2, id);
System.Console.ReadLine();
}
private static void HandleTask(Task delayTask, int id)
{
delayTask.ContinueWith(p => Console.WriteLine(string.Format("Task {0} was cancelled.", id)), TaskContinuationOptions.OnlyOnCanceled);
delayTask.ContinueWith(p => Console.WriteLine(string.Format("Task {0} was completed.", id)), TaskContinuationOptions.OnlyOnRanToCompletion);
}
static Task Delay(int delayTime, System.Threading.CancellationToken token)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
if (delayTime < 0) throw new ArgumentOutOfRangeException("Delay time cannot be under 0");
System.Threading.Timer timer = null;
timer = new System.Threading.Timer(p =>
{
timer.Dispose(); //stop the timer
tcs.TrySetResult(null); //timer expired, attempt to move task to the completed state.
}, null, delayTime, System.Threading.Timeout.Infinite);
token.Register(() =>
{
timer.Dispose(); //stop the timer
tcs.TrySetCanceled(); //attempt to mode task to canceled state
});
return tcs.Task;
}
}
}
public static void DelayExecute(double delay, Action actionToExecute)
{
if (actionToExecute != null)
{
var timer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(delay)
};
timer.Tick += (delegate
{
timer.Stop();
actionToExecute();
});
timer.Start();
}
}
您可以下载Visual Studio Async CTP并使用TaskEx.Delay
AutoResetEvent pause = new AutoResetEvent(false);
Task timeout = Task.Factory.StartNew(()=>{
pause.WaitOne(1000, true);
});
var wait = new TaskCompletionSource<bool>();
using (new Timer(_ => wait.SetResult(false), null, delay, Timeout.Infinite))
await wait.Task;
如果要在.NET 4.0上使用此代码,您需要安装Microsoft.Bcl.Async NuGet包。
await
关键字是 C# 语言的一部分,与 .NET Framework 版本是分开的。问题在于 Task<T>
没有 GetAwaiter
,而 await
依赖于它。Microsoft.Bcl.Async 提供了这个功能。我更新了我的答案,提到了这个 NuGet 包。 - Edward Brey
Task.Delay()
并不是让一个任务进入睡眠状态,而是创建了一个新的Task
。如果你等待它完成,那么它会让一个任务在指定的时间内进入睡眠状态。这是你要找的吗?一个在指定时间后完成的Task
? - svickThread.Sleep
几乎总是一个错误。 - Eli Arbel