5

好的,所以我了解如何使用CancellationTokenSource. 在我看来,Task“那种”类型会自动处理此异常 - 它将Task's设置Status为 Cancelled。

现在你实际上仍然必须处理OperationCancelledException. 否则异常冒泡到Application.UnhandledException. Task 本身可以识别它并在内部进行一些处理,但是您仍然需要将调用代码包装在 try 块中以避免未处理的异常。有时,这似乎是不必要的代码。如果用户按下取消,则取消Task(显然任务本身也需要处理它)。我觉得不需要任何其他代码要求。只需检查Status属性以了解任务的完成状态。

从语言设计的角度来看,这有什么具体原因吗?有没有其他方法可以将Status属性设置为取消?

4

2 回答 2

5

CancellationToken如果您使用创建任务,则可以将任务的状态设置为取消TaskCompletionSource

var tcs = new TaskCompletionSource();
var task = tcs.Task;
tcs.SetCancelled();

除此之外,您只能取消Task运行CancellationToken

于 2014-12-17T13:24:12.450 回答
4

您只需将调用代码包装在请求结果或等待任务完成的 try/catch 块中 - 这些是引发异常的情况。例如,创建任务的代码不会抛出该异常。

目前尚不清楚替代方案是什么 - 例如:

string x = await GetTaskReturningString();

这里我们从来没有一个变量引用任务,所以我们不能明确地检查状态。我们必须使用:

var task = GetTaskReturningString();
string x = await task;
if (task.Status == TaskStatus.Canceled)
{
    ...
}

...这不仅不太方便,而且还将“发生了什么事”代码的处理移到了正常成功路径的中间。

此外,通过处理异常取消,如果您有多个操作,您可以将所有处理放在一个 catch 块中,而不是单独检查每个任务:

try
{
    var x = await GetFirstTask();
    var y = await GetSecondTask(x);
}
catch (OperationCanceledException e)
{
    // We don't care which was canceled
}

相同的论点适用于在堆栈中第一次取消发生的任何地方处理取消-如果您有很深的异步方法堆栈,最深方法中的取消将导致最顶层的任务被取消,就像正常的异常传播一样.

于 2014-12-17T13:23:28.633 回答