【问题标题】:Try/Catch Wrap Around Task.Run not Handling ExceptionTry/Catch Wraparound Task.Run 不处理异常
【发布时间】:2016-09-13 22:11:59
【问题描述】:

我一直在学习使用 TPL,但对我从 article 收集的示例有疑问。我复制并粘贴了与 Task.Run 示例中完全相同的代码,但收到一条错误消息,指出未处理异常:

private async void button1_Click(object sender, EventArgs e)
{
    try
    {
        await Task.Run(() =>
        {
            Thread.Sleep(1000);
            throw new InvalidOperationException("Hi!");
        });
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

这是错误的图片:

这个代码示例是过时了还是我遗漏了什么?

【问题讨论】:

  • 我认为你需要使用invoke(),但我不确定
  • 如果您不在调试器中运行此代码,我怀疑您会发现显示消息框 - 您尝试过吗?异常不是由运行任务的线程中的代码处理的,但是您要单独捕获它...我怀疑调试器在这里有点误导。
  • @JonSkeet 你是对的。不使用调试器时它工作正常

标签: c# .net try-catch task-parallel-library task


【解决方案1】:

正如Stephen 的正确答案中所述,这仅在调试器打开时才会发生。使用这个简单的解决方法,您可以在 Task.Run(); 的“外部”重新抛出异常;

Exception exceptionOut = null;

await Task.Run(() =>
{
    try
    {
        // Your code
    }
    catch (Exception exceptionIn)
    {
        exceptionOut = exceptionIn;
    }
});

if (exceptionOut != null)
    throw exceptionOut;

【讨论】:

    【解决方案2】:

    这只是一个误导性的调试器消息。

    实际发生的是异常被抛出,然后被 .NET 框架(不是用户代码)捕获,然后放置在任务上。

    因此,虽然技术上错误消息是正确的(它被 .NET 框架捕获 - 未由用户代码处理),但在这种情况下它不是很有帮助。

    不幸的是,调试器也没有很多替代品。当异常离开用户代码时,调试器无法“展望未来”来知道异常将被放置在特定任务上,并且您的代码将await该任务。它必须立即决定是否通知您,而不知道该任务是否将是awaited。

    【讨论】:

    • 感谢您的解释!
    【解决方案3】:

    您的 try/catch 运行异步操作,因此不会保留异步操作,因为不能保证在遇到异常时代码位于该位置。尝试在 Task.Run(() => {..}); 中包含 try/catch

    【讨论】:

    • OP 正在等待 try 块中的任务,因此异常将被传播然后被捕获。我怀疑“未由用户代码处理”在这里有点不精确。
    猜你喜欢
    • 2011-04-01
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多