C# 是否有其他方法将Task.Status设置为Cancelled

C# 是否有其他方法将Task.Status设置为Cancelled,c#,.net,task-parallel-library,cancellation,cancellationtokensource,C#,.net,Task Parallel Library,Cancellation,Cancellationtokensource,好的,我了解了如何使用CancellationTokenSource取消任务。在我看来,任务类型“种类”自动处理此异常-它将任务的状态设置为已取消 现在,您实际上还必须处理操作canceleredexception。否则,异常会冒泡到应用程序。未处理的异常。任务本身可以识别它并在内部进行一些处理,但是您仍然需要将调用代码包装在try块中以避免未处理的异常。有时,这似乎是不必要的代码。如果用户按cancel,则取消任务(显然任务本身也需要处理它)。我觉得不需要任何其他代码要求。只需检查任务完成状态

好的,我了解了如何使用
CancellationTokenSource
取消任务。在我看来,
任务
类型“种类”自动处理此异常-它将
任务
状态
设置为已取消

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


从语言设计的角度来看,这有什么具体的原因吗?是否有其他方法将
Status
属性设置为cancelled?

您只需将调用代码包装在一个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
}

同样的参数也适用于在堆栈中发生第一次取消的任何位置处理取消-如果异步方法堆栈较深,则最深方法中的取消将导致最顶端的任务被取消,就像正常的异常传播一样。

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

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

除此之外,您只能使用
取消令牌取消正在运行的
任务
,谢谢。答案的第二部分明确(并解释)了设计决策和推理。现在我同意try/catch方法可能比我最初的想法更简洁。但是,我不明白为什么我不必在try块中包装调用代码-如果我不包装,则
操作取消异常
将使应用程序崩溃?@Simon:我的观点是,需要包装的不是启动任务的代码,而是等待结果的代码。。。即使如此,也只是在最高层次。我会澄清的。我想我理解这个场景!有趣的。。。我将对此进行调查,尽管乔恩的回答稍微改变了我的想法。@Simon Jon Skeet的回答当然是正确的。这可能是@l3arnon-Brilliant的一个例子——这正是我的问题!Y问题,啊,我是说X…,呃:)