前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >2019-7-13-FirstChanceException原理

2019-7-13-FirstChanceException原理

作者头像
黄腾霄
发布2020-06-10 12:01:43
6980
发布2020-06-10 12:01:43
举报
文章被收录于专栏:黄腾霄的博客

异常处理是代码中很重要的一项注意点。但是有时候一些不恰当的异常处理,反而会影响我们在代码运行时的调试。


出现问题

假如我们有这么一段代码,我期望调用Bar方法,输出“黄腾霄是帅哥”。

但是在实际运行中,其中的一个方法Foo抛出了一个异常。

而作为代码书写者,为了确保软件的正常运行,将这个方法的所有异常都吞掉了。

此时导致的结果就是,用户端看到软件运行正常,但是没有期望的输出

代码语言:javascript
复制
		static void Main(string[] args)
        {
            Bar();
        }

        static void Bar()
        {
            try
            {
                Foo();
                Console.WriteLine("黄腾霄是帅哥");
            }
            catch (Exception)
            {
                // ignored
            }
        }

        static void Foo()
        {
            throw new InvalidOperationException("黄腾霄是逗比");
        }

修改代码

此时就需要使用我们这篇博客的主角——AppDomain.FirstChanceException

我们试着对代码进行如下修改

代码语言:javascript
复制
		private static int n = 1;

        static void Main(string[] args)
        {
            AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
            {
                 Console.WriteLine(eventArgs.Exception);
            };
            Bar();
        }

        static void Bar()
        {
            try
            {
                Foo();
                Console.WriteLine("黄腾霄是帅哥");
            }
            catch (Exception)
            {
                // ignored
            }
        }

        static void Foo()
        {
            throw new InvalidOperationException("黄腾霄是逗比");
        }

我们可以看到异常信息被输出到屏幕了,并且此时程序仍然正常运行,没有出现奔溃

什么是FirstChanceException

FirstChanceException是一个异常通知事件。当一个AppDomain中引发任何异常的时候,CLR会优先触发FirstChanceException, 当其被处理后,才会开始寻找原始异常的处理函数。

例如我们在Barcatch块中添加一些日志输出,会发现这些输出出现在FirstChanceException的输出之后

代码语言:javascript
复制
		static void Bar()
        {
            try
            {
                Foo();
                Console.WriteLine("黄腾霄是帅哥");
            }
            catch (Exception)
            {
                Console.WriteLine("不许你侮辱我家男神");
            }
        }

对于FirstChanceException,需要注意的是它只是一个通知。它会在任何引发异常的地方(throw)的地方,触发事件。但是它并不能作为异常统一处理的地方。

思考

  • 假如我们在FirstChanceException的处理函数中抛出一个异常会怎么样?

请你绝对不要做出这种事情。我们刚刚说了FirstChanceException会在任何引发异常的地方触发该事件,如果你在FirstChanceException的处理函数中再次抛出异常,即使使用了trycatch,也会出现死循环,最终导致stackoverflow。

所以不能够在这个方法里面写出任何可能出现异常的代码。

  • 使用诸如throw;这样的语句是否会对同一个异常再次触发FirstChanceException?

参见下面这个例子,请问我被侮辱了几次?

代码语言:javascript
复制
		static void Main(string[] args)
        {
            AppDomain.CurrentDomain.FirstChanceException += (sender, eventArgs) =>
            {
                Console.WriteLine($"黄腾霄被侮辱次数+{n++}");
            };
            try
            {
                try
                {
                    try
                    {
                        throw new InvalidOperationException("黄腾霄是逗比");
                    }
                    catch (Exception e)
                    {
                        throw new ArgumentException("不许你侮辱我家男神", e);
                    }
                }
                catch (Exception e)
                {
                    ExceptionDispatchInfo.Capture(e).Throw();
                }
            }
            catch (Exception e)
            {
                throw;
            }
        }

答案是4次。实际上FirstChanceException是每次引发异常的地方都会触发。而无论是 ExceptionDispatchInfo.Capture(e).Throw();还是throw;都只是保证了该异常的堆栈可以连续,而这个异常仍然会被重新引发一次。

参考链接:


本文会经常更新,请阅读原文: https://xinyuehtx.github.io/post/FirstChanceException%E5%8E%9F%E7%90%86.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

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

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-07-13 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 出现问题
  • 修改代码
  • 什么是FirstChanceException
  • 思考
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档