有没有其他方法可以将 Task.Status 设置为 Canceled

Sim*_*mon 5 .net c# task-parallel-library cancellation cancellationtokensource

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

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

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

i3a*_*non 5

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

var tcs = new TaskCompletionSource();
var task = tcs.Task;
tcs.SetCancelled();
Run Code Online (Sandbox Code Playgroud)

除此之外,您只能Task使用CancellationToken


Jon*_*eet 4

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

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

string x = await GetTaskReturningString();
Run Code Online (Sandbox Code Playgroud)

这里我们从来没有引用任务的变量,因此我们无法显式检查状态。我们必须使用:

var task = GetTaskReturningString();
string x = await task;
if (task.Status == TaskStatus.Canceled)
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

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