简体   繁体   English

你能解释一下为什么如果我不等待异步任务就不会发现异常?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM