[英]Can you explain why the exception is not caught if I do not await an async task?
Starting from an issue I had on my code, I've created this simple app to recreate the problem: 从我在代码上遇到的问题开始,我创建了这个简单的应用程序来重新创建问题:
private async void button1_Click(object sender, EventArgs e)
{
Task task = Task.Run(() =>
{
TestWork();
});
try
{
await task;
MessageBox.Show("Exception uncaught!");
}
catch (Exception) { MessageBox.Show("Exception caught!"); }
}
private async void button2_Click(object sender, EventArgs e)
{
Task task = TestWork();
try
{
await task;
MessageBox.Show("Exception uncaught!");
}
catch (Exception) { MessageBox.Show("Exception caught!"); }
}
private async Task TestWork()
{
throw new Exception();
}
The code for button1_Click
will not catch the exception. button1_Click
的代码不会捕获异常。 I've verified that this is because I'm not awaiting the TestWork
async method. 我已经证实这是因为我没有等待TestWork
异步方法。 Indeed I've a warning message from Visual Studio that inform me I'm not awaiting the method. 事实上,我从Visual Studio发出一条警告信息告诉我,我不是在等待这种方法。 However the solution compile and I'm scared this can happen somewhere else in my code if I use extensively the async/await. 然而解决方案编译,我害怕这可能发生在我的代码中的其他地方,如果我广泛使用async / await。 So can you please explain the reason and peraphs give some golden rule to avoid it? 那么请你解释一下原因,并且peraphs给出一些避免它的黄金法则?
PS: It works if in the code for button1_Click
I write: PS:如果在button1_Click
的代码中我写的是:
Task task = Task.Run(async () =>
{
await TestWork();
});
In your first button1_Click
implementation, you are ignoring the result of the Task
returned by TestWork
. 在第一个button1_Click
实现中,您忽略了TestWork
返回的Task
的结果。
In your modified version, the await
checks for an Exception and propogates it for you to catch. 在您的修改版本中, await
检查Exception并传播它以供您捕获。
In fact, the compiler warning you are seeing is normally important. 实际上,您看到的编译器警告通常很重要。 If TestWork
actually ran something on a different thread, then because the wrapper Task
in your first implementation doesn't wait for TestWork
to complete, it would just complete itself as soon as TestWork
had started. 如果TestWork
实际上在不同的线程上运行了某些东西,那么因为第一个实现中的包装器Task
不等待TestWork
完成,所以只要TestWork
启动它就会自动完成。
Writing it this way makes it clearer: 用这种方式写它会让它更清晰:
Task task = Task.Run( () =>
{
Task t = TestWork();
// ignore t
}
);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.