给出类似方法的签名
Taks<int> ComputeAsync(..., CancellationToken cancellationToken)
,期望返回的任务完成
RanToCompletion
(和Result
集)或Faulted
(和Exception
集)或Canceled
,如果cancellationToken
请求取消当将该方法实现为async
方法时,如何实现?
通过测试,我发现从async方法中抛出OperationCanceledException
显然可以完成处于Canceled
状态的任务(无论异常中包装了什么令牌,无论该令牌是否IsCancellationRequested
):
var tasks = new[]
{
Task.FromResult(42),
Task.FromException<int>(new Exception("Boom!")),
Task.FromCanceled<int>(new CancellationToken(true)),
Task.FromException<int>(new OperationCanceledException(new CancellationToken(true)))
};
async Task<int> Await(Task<int> task) => await task;
foreach (var t in tasks)
Console.WriteLine($"{t.Status} - {Await(t).Status}");
输出:
RanToCompletion - RanToCompletion
Faulted - Faulted
Canceled - Canceled
Faulted - Canceled
但是,我似乎找不到任何有关上述行为的文档或其他信息。可以跨框架版本依赖它吗?
如果答案是肯定的,那么cancellationToken.ThrowIfCancellationRequested()
会做正确的事,但是如果没有抓住OperationCanceledException
(可能来自await
个任务),则可以设置任务Canceled
尽管!cancellationToken.IsCancellationRequested
。因此,为了获得可预测和正确的结果,我们是否需要将每个可取消的异步方法包装到try / catch中,以确保没有抛出OCE,除非它在正确的CancellationToken
上,或者是否有更优雅的方法? / p>
如果答案是否定的,那么我们是否必须退回到TaskCompletionSource
的东西上?
答案 0 :(得分:0)
从您的示例开始-尚不清楚您使用cancelToken的意图。因此,我将不得不从我的用法中谈一谈。我们使用Windows服务,需要知道是否已使用OnStop事件。 TokenSource对象具有Cancel方法,以向Task发出信号,告知我们需要停止操作。令牌布尔值指示请求取消。通过抛出OperationCancelled-您可以捕获该值并优雅地处理它。都是以控制任务的同步的名义。如果这样做,您的方案将在某种程度上具有相同的需求。 附加说明7/16/2018:
您在问题中喊出签名(在Task上正确拼写)
Task<int> ComputeAsync(..., CancellationToken cancellationToken)
但是您的示例-构建了一个在所有任务中都不使用该签名的任务数组。您的示例太不完整,无法给出答案。 (似乎您不了解任务的签名)。当您使用取消令牌调用任务时,您的任务动作就是签名示例中的省略号-并且您没有显示要传递给任务的内容。
您使用的Task.FromResult表示-返回此结果。
如果在'FromResult'方法上使用Visual Studio F12,您将看到带有此注释的源代码,指出该状态
Summary:
// Creates a System.Threading.Tasks.Task`1 that's completed
successfully with the
// specified result.
这完全与您的问题不符。 这是FromResult用于什么的stackoverflow答案 What is the use for Task.FromResult<TResult> in C#