当前位置: 首页 > news >正文

C#/.NET 如何在第一次机会异常 FirstChanceException 中获取比较完整的异常堆栈

FirstChangeException 事件中,我们通常只能拿到异常堆栈的第一帧,这对于我们捕捉到异常是好的,但对分析第一次机会异常可能并不利。

本文介绍如何在 FirstChangeException 事件中拿到比较完整的异常堆栈,而不只是第一帧。


本文内容

    • 第一次机会异常
    • 获取较完整的第一次机会异常堆栈

第一次机会异常

.NET 程序代码中的任何一段代码,在刚刚抛出异常,还没有被任何处理的那一时刻,AppDomain 的实例会引发一个 FirstChanceException 事件,用于通知此时刚刚开始发生了一个异常。

这时,这个异常还没有寻找任何一个可以处理它的 catch 块,在此事件中,你几乎是第一时间拿到了这个异常的信息。

监听第一次机会异常的代码是这个样子的:

private void WalterlvDemo()
{
    AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;
}

private void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
    // 在这里,可以通过 e.Exception 来获取到这个异常。
    Console.WriteLine(e.Exception.ToString());
}

只不过,在这里我们拿到的异常堆栈只有第一帧,因为这个时候,还没有任何 catch 块捕捉到这个异常。比如,我们只能拿到这个:

System.NotSupportedException: BitmapMetadata 在 BitmapImage 上可用。
   在 System.Windows.Media.Imaging.BitmapImage.get_Metadata()

一点知识Exception 实例的异常堆栈,是从第一次抛出异常的地方开始,到第一个 catch 它的地方结束,除非这个 catch 块中继续只用 throw; 抛出才继续向外延伸到下一个 catch

另外,你也可以用 ExceptionDispatchInfo 让内部异常的堆栈也连接起来,详见我的另一篇博客:

  • 使用 ExceptionDispatchInfo 捕捉并重新抛出异常 - 吕毅

获取较完整的第一次机会异常堆栈

我们需要等到 FirstChanceException 事件中的异常被 catch 到,就能获取到第一次抛出的地方到 catch 处之间的所有帧。

所以,我们只需要稍作延迟,即可拿到较完整的异常堆栈:

private void WalterlvDemo()
{
    AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;
}

private async void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
{
    // 刚刚进入第一次机会异常事件的时候,异常堆栈只有一行,因为此时还没有任何地方 catch。
    // 现在等待一点点时间,使得异常的堆栈能够延伸到 catch。等待多长不重要,关键是为了让异常得以找到第一个 catch。
    await Task.Delay(10);

    // 在这里,可以通过 e.Exception 来获取到这个异常。
    Console.WriteLine(e.Exception.ToString());
}

这样,我们可以得到:

System.NotSupportedException: BitmapMetadata 在 BitmapImage 上可用。
   在 System.Windows.Media.Imaging.BitmapImage.get_Metadata()
   在 System.Windows.Media.Imaging.BitmapFrame.Create(BitmapSource source)
   在 Walterlv.Demo.Exceptions.Foo.Take(string fileName)

这里,等待多长时间是不重要的,只要不是 0 就好。因为我们只需要当前调用堆栈中的异常处理执行完成即可。

关于等待时间,可以阅读我的另一篇博客:

  • C#/.NET 中 Thread.Sleep(0), Task.Delay(0), Thread.Yield(), Task.Yield() 不同的执行效果和用法建议 - 吕毅

如果需要对此异常进行后续的分析,可以参考我的另一篇博客:

  • C#/.NET 如何获取一个异常(Exception)的关键特征,用来判断两个异常是否表示同一个异常 - 吕毅

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

知识共享许可协议

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系。

相关文章:

  • C#/.NET 使用 git 命令行来操作 git 仓库
  • C#/.NET 中启动进程时所使用的 UseShellExecute 设置为 true 和 false 分别代表什么意思?
  • WPF 的命令的自动刷新时机——当你 CanExecute 会返回 true 但命令依旧不可用时可能是这些原因
  • 将 C++/WinRT 中的线程切换体验带到 C# 中来(WPF 版本)
  • 如何在 MSBuild 的项目文件 csproj 中获取绝对路径
  • C# 跨设备前后端开发探索
  • MSBuild 如何编写带条件的属性、集合和任务 Condition?
  • WPF 像素着色器入门:使用 Shazzam Shader Editor 编写 HLSL 像素着色器代码
  • 如何快速自定义 Visual Studio 中部分功能的快捷键
  • C# 8.0 如何在项目中开启可空引用类型的支持
  • C# 8.0 可空引用类型中的各项警告/错误的含义和示例代码
  • C# 可空引用类型 NullableReferenceTypes 更强制的约束:将警告改为错误 WarningsAsErrors
  • ClearType 的原理:Windows 上文本的亚像素控制
  • 使用 7-Zip 的命令行版本来压缩和解压文件
  • 在项目文件 csproj 中或者 MSBuild 的 Target 中使用 % 引用集合中每一项的属性
  • 【Leetcode】101. 对称二叉树
  • hexo+github搭建个人博客
  • CAP理论的例子讲解
  • Java超时控制的实现
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • Median of Two Sorted Arrays
  • Shadow DOM 内部构造及如何构建独立组件
  • Shell编程
  • SSH 免密登录
  • 和 || 运算
  • 什么是Javascript函数节流?
  • 突破自己的技术思维
  • 小试R空间处理新库sf
  • 云大使推广中的常见热门问题
  • 在weex里面使用chart图表
  • #我与Java虚拟机的故事#连载02:“小蓝”陪伴的日日夜夜
  • $.ajax()
  • (Matalb回归预测)PSO-BP粒子群算法优化BP神经网络的多维回归预测
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (附源码)ssm基于jsp高校选课系统 毕业设计 291627
  • (三)uboot源码分析
  • (转载)Linux网络编程入门
  • .cfg\.dat\.mak(持续补充)
  • .Net CF下精确的计时器
  • .net MySql
  • .net企业级架构实战之7——Spring.net整合Asp.net mvc
  • .NET企业级应用架构设计系列之结尾篇
  • .NET应用架构设计:原则、模式与实践 目录预览
  • /3GB和/USERVA开关
  • @Autowired和@Resource装配
  • [@Controller]4 详解@ModelAttribute
  • [145] 二叉树的后序遍历 js
  • [20180224]expdp query 写法问题.txt
  • [8-23]知识梳理:文件系统、Bash基础特性、目录管理、文件管理、文本查看编辑处理...
  • [ABC294Ex] K-Coloring
  • [AX]AX2012 AIF(四):文档服务应用实例
  • [Intel Edison开发板] 05、Edison开发基于MRAA实现IO控制,特别是UART通信
  • [iOS]如何删除工程里面用cocoapods导入的第三方库
  • [LaTex]arXiv投稿攻略——jpg/png转pdf
  • [LeetCode]: 145: Binary Tree Postorder Traversal