我忽略缺少await的异步调用的编译器警告是正确的吗?

30

我有以下方法,当我的Metro应用程序的某个部分发生异常时,该方法会被触发

void Model_ExceptionOccured(Exception ex)
{
    var dlg = new Windows.UI.Popups.MessageDialog("An exception occured during verification: " + ex.Message, "Exception");
    dlg.ShowAsync();
}

'dlg.ShowAsync()'调用是异步的,但我不想等待结果。虽然如此,编译器为其生成了一个警告:

由于未等待此调用的完成,当前方法的执行将在调用完成之前继续进行。考虑将'await'运算符应用于调用的结果。

我需要在意吗?除了消除警告之外,是否有其他原因我应该添加await关键字?

3个回答

28

在VS2012中,他们更改了未观察到的任务异常的默认策略。默认行为是终止进程。 - alexm
您提供的链接显示了 VB 特定的错误。您是否有类似 C# 的参考资料? - alexm
链接中可以看到:“在大多数情况下,这种行为并不是您所期望的。通常,调用方法的其他方面依赖于调用的结果,或者至少,在包含调用的方法返回之前,期望调用的方法完成。”这有一定道理,但如果您将ShowAsync包装在try块中,并采用链接建议的使用任务进行捕获(Task showAsyncResult = dlg.ShowAsync();),那么您仍然是安全的,甚至是最佳实践? - ruffin

6
问题在于,如果 dlg.ShowAsync(); 中的代码抛出异常,它将无法处理,并且稍后将被 Finalizer 线程重新抛出,可能导致程序终止。
实际发生的情况取决于.NET 异常策略
MSDN 上的这篇文章提到:
“如果您不等待传播异常的任务,也不访问其 Exception 属性,则该异常将根据 .NET 异常策略进行升级,当垃圾回收任务时。”
当 VS 2012 最终发布时,默认策略更改为忽略未处理的任务异常。

-1
我遇到了同样的问题,这是我的解决方案:
我创建了一个Task对象,并将async函数的输出分配给Task对象,然后使用Timer定期检查任务的状态。
以下是一个简单的示例:(在我的Update_Click事件处理程序中)
StatusLabel.Text = "Preparing " + feedArticleList1.Feed.Title;
UpdateCheck.Enabled = true;
UpdateTask = feedArticleList1.Feed.UpdateFeedAsync();

稍后,在我的计时器事件处理程序中,我会检查UpdateTask.Status:
switch (UpdateTask.Status)
{
    case TaskStatus.Canceled:
    case TaskStatus.Created:
    case TaskStatus.Running:
    case TaskStatus.WaitingForActivation:
    case TaskStatus.WaitingForChildrenToComplete:
    case TaskStatus.WaitingToRun:
        StatusLabel.Text = UpdateTask.Status.ToString();
        break;
    case TaskStatus.RanToCompletion:
        StatusLabel.Text = "Update Complete " + DateTime.Now.ToShortTimeString();
        UpdateCheck.Enabled = false;
        break;
    case TaskStatus.Faulted:
        throw (UpdateTask.Exception);
    default:
        break;
}

2
您可以使用任务异常和ContinueWith来实现相同的效果 - 这似乎是在重新发明轮子,特别是将轮询引入异步方法中。 - Mathieson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接