动机
C#5.0异步/等待构造非常棒,但遗憾的是,微软只展示了.NET 4.5和VS 2012的候选版本,这些技术将在我们的项目中得到广泛采用需要一些时间.
在Stephen Toub的Asynchronous methods,C# iterators,and Tasks中,我找到了一个可以很好地用于.NET 4.0的替代品.还有十几个其他实现甚至可以在.NET 2.0中使用该方法,尽管它们看起来很少过时且功能较少.
例
所以现在我的.NET 4.0代码看起来像(注释部分显示它是如何在.NET 4.5中完成的):
//private async Task ProcessMessageAsync() private IEnumerable<Task> ProcessMessageAsync() { //var udpReceiveResult = await udpClient.ReceiveAsync(); var task = Task<UdpAsyncReceiveResult> .Factory .FromAsync(udpClient.BeginReceive,udpClient.EndReceive,null); yield return task; var udpReceiveResult = task.Result; //... blah blah blah if (message is BootstrapRequest) { var typedMessage = ((BootstrapRequest)(message)); // !!! .NET 4.0 has no overload for CancellationTokenSource that // !!! takes timeout parameter :( var cts = new CancellationTokenSource(BootstrapResponseTimeout); // Error here //... blah blah blah // Say(messageIPEndPoint,responseMessage,cts.Token); Task.Factory.Iterate(Say(messageIPEndPoint,cts.Token)); } }
看起来有点难看虽然它能完成这项工作
这个问题
在.NET 4.5中使用CancellationTokenSource时,有一个构造函数将时间跨度作为超时参数,因此生成的CancellationTokenSource在指定的时间段内取消.
.Net 4.0无法超时,那么在.Net 4.0中这样做的正确方法是什么?
解决方法
这真的与async / await有关吗?看起来你只需要一种取消令牌的方法,独立于异步/等待,对吗?在这种情况下,您可以简单地创建一个在超时后调用取消的Timer吗?
new Timer(state => cts.Cancel(),null,BootstrapResponseTimeout,Timeout.Infinite);
编辑
我上面的初步回答是基本思路,但是在Is CancellationTokenSource.CancelAfter() leaky?中可以找到更强大的解决方案(实际上是你正在寻求的构造函数的.Net 4.5实现).这是一个可用于根据该代码创建超时令牌的函数.
public static CancellationTokenSource CreateTimeoutToken(int dueTime) { if (dueTime < -1) { throw new ArgumentOutOfRangeException("dueTime"); } var source = new CancellationTokenSource(); var timer = new Timer(self => { ((Timer)self).Dispose(); try { source.Cancel(); } catch (ObjectDisposedException) {} }); timer.Change(dueTime,-1); return source; }