在键盘事件中使用CancellationToken调用Task.Delay时的TaskCanceledException

时间:2013-12-11 01:59:18

标签: c# asynchronous windows-runtime cancellationtokensource cancellation-token

我正在尝试延迟处理WinRT中键盘事件调用的方法(示例中的SubmitQuery()),直到一段时间内没有其他事件(在这种情况下为500毫秒)。

我只想在用户输入完成后运行SubmitQuery()。

使用下面的代码,当Task.Delay(500,cancellationToken.Token)时,我不断收到System.Threading.Tasks.TaskCanceledException;叫做。我在这做错了什么?

CancellationTokenSource cancellationToken = new CancellationTokenSource();

private async void SearchBox_QueryChanged(SearchBox sender, SearchBoxQueryChangedEventArgs args)
{

        cancellationToken.Cancel();
        cancellationToken = new CancellationTokenSource();

    await Task.Delay(500, cancellationToken.Token);

    if (!cancellationToken.IsCancellationRequested)
    {
        await ViewModel.SubmitQuery();
    }
}

5 个答案:

答案 0 :(得分:40)

如果使用空操作添加ContinueWith(),则不会抛出异常。异常被捕获并传递给{task.Exception中的ContinueWith()属性1}}。但它可以帮助您避免编写可以解释代码的尝试/捕获。

await Task.Delay(500, cancellationToken.Token).ContinueWith(tsk => { });

答案 1 :(得分:15)

这是可以预料的。当您取消旧的Delay时,它会引发异常;这就是取消的方式。您可以在try周围放置一个简单的catch / Delay来捕获预期的异常。

请注意,如果你想做这样的基于时间的逻辑,Rx比async更自然。

答案 2 :(得分:0)

奇怪的是,取消异常似乎仅在取消令牌位于Task.Delay上时引发。将令牌放在ContinueWith上,不会引发取消异常:

Task.Delay(500).ContinueWith(tsk => {
   //code to run after the delay goes here
}, cancellationToken.Token);

如果您确实想捕获任何取消异常,则可以将其链接到另一个.ContinueWith()上-该异常将被传递到那里。

答案 3 :(得分:0)

抑制等待的任务异常的另一种简便方法是将该任务作为单个参数传递给Task.WhenAny

  

创建一个任务,该任务将在提供的任何任务完成时完成。

await Task.WhenAny(Task.Delay(500, token)); // Ignores the exception

此方法的一个问题是它不能清楚地传达其意图,因此建议添加注释。另一个原因是它导致分配(因为params签名中的Task.WhenAny)。

答案 4 :(得分:0)

我认为应该对它为什么会这样工作进行评论。

文档实际上是错误的或写的不清楚 Task.Delay 方法的 TaskCancelledException。 Delay 方法本身永远不会抛出该异常。它将任务转移到取消状态,而真正引发异常的是await。此处使用 Task.Delay 方法无关紧要。它与任何其他取消的任务的工作方式相同,这就是取消预期的工作方式。这实际上解释了为什么添加延续会神秘地隐藏异常。因为它是由 await 引起的。