我正在尝试延迟处理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();
}
}
答案 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
引起的。