未捕获异步方法中引发的异常 - 为啥?

Posted

技术标签:

【中文标题】未捕获异步方法中引发的异常 - 为啥?【英文标题】:Exception thrown in async method is not caught - why?未捕获异步方法中引发的异常 - 为什么? 【发布时间】:2021-12-26 04:10:09 【问题描述】:

我很难理解 async/await 在各种非快乐路径情况下的工作原理。例如,我有以下代码:

    class Program
    
        static void Main(string[] args)
        
            Do();
            Console.ReadLine();
        

        private static void Do()
        
            TaskScheduler.UnobservedTaskException += (s, e) =>
            
                Console.WriteLine($"Unobserved Exception : e.Exception.Message");
                e.SetObserved();
            ;
            
            try
                            
                ThrowsAsync();
            
            catch (Exception ex)
            
                Console.WriteLine($"Caught in try/catch  : ex.Message");
            
        

        private static async Task ThrowsAsync()
            
            Console.WriteLine("Throwing");
            throw new Exception("FAILURE");
        
    

有两点我不明白:

    ThrowsAsync 方法是异步的,但是它不包含任何await。我假设在这种情况下,该方法将像“正常”同步方法一样执行。但是,它抛出的异常永远不会在 catch 块中捕获。 试图以某种方式捕获异常,我为TaskScheduler.UnobservedTaskException 添加了处理程序。但是,它永远不会被执行。这是为什么呢?

我知道如果我等待ThrowsAsync,就会捕获异常。不过,我正在尝试更好地了解它的工作原理。

我正在使用 .NET 5 和基于 Linux 的操作系统运行该代码。

【问题讨论】:

***.com/questions/19865523/… 第二个this可以解释一下。对于第一个 ThrowsAsync 是异步的并返回一个 Task 所以在等待之前它不应该抛出。 也适用于第一点 - this. @GuruStron 关于UnobservedTaskException。我试图遵循链接 SO 中的建议。我在Do 方法的末尾添加了以下内容:Console.WriteLine("GC"); Thread.Sleep(100); GC.Collect(); GC.WaitForPendingFinalizers();。它没有改变任何东西。我看到控制台中打印了“GC”,仅此而已。 @Loreno 你可以和this article 一起去硬核,或者阅读斯蒂芬·克利里的博客和书籍(博客之前链接过)。 【参考方案1】:

    正如 Stephen Cleary 所描述的例如in this blog post - async 方法的状态机将从您的代码中捕获异常并将它们放置在返回的任务中,即方法调用不会抛出,您将能够捕获异常如果await 结果。

    至于TaskScheduler.UnobservedTaskException - 查看this answer 并确保在Release 模式下运行代码。

【讨论】:

以上是关于未捕获异步方法中引发的异常 - 为啥?的主要内容,如果未能解决你的问题,请参考以下文章

vb.net制作的Excel文件 未捕获通过反射调用的方法而引发的异常

未使用 await 调用时在异步方法中捕获异常

VS2010 F5调试时出现:“ 尝试运行项目时出错:未捕获通过反射调用的方法引发的异常”解决

为啥我的 JScript(Windows 脚本宿主)在未捕获的异常中以 0 退出?

为啥使用Try,Catch捕获异常,程序依然Crash

在任务中捕获异常的最佳方法是啥?