.NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)

栏目: ASP.NET · 发布时间: 4年前

内容简介:使用 Visual Studio 可以帮助我们在发生异常的时候中断,便于我们调试程序出现异常那一时刻的状态。如果没有 Visual Studio 的帮助(例如运行已发布的程序),当出现某个或某些特定异常的时候如何能够迅速进入中断的环境来调试呢?本文介绍如何实现在发生特定异常时中断,以便调查此时程序的状态的纯代码实现。.NET 程序代码中的任何一段代码,在刚刚抛出异常,还没有被任何处理的那一时刻,AppDomain 的实例会引发一个 FirstChanceException 事件,用于通知此时刚刚开始发生了一

使用 Visual Studio 可以帮助我们在发生异常的时候中断,便于我们调试程序出现异常那一时刻的状态。如果没有 Visual Studio 的帮助(例如运行已发布的程序),当出现某个或某些特定异常的时候如何能够迅速进入中断的环境来调试呢?

本文介绍如何实现在发生特定异常时中断,以便调查此时程序的状态的纯代码实现。

第一次机会异常

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

于是我们可以通过监听第一次机会异常来获取到异常刚刚发生那一刻而还没有被 catch 的状态:

using System;
using System.IO;
using System.Runtime.ExceptionServices;

namespace Walterlv.Demo.DoubiBlogs
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;

            // 这里是程序的其他代码。
        }

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

在第一次机会异常处中断

我在这篇博客中举了一个例子来说明如何在发生异常的时候中断,不过是使用 Visual Studio:

那么现在我们使用第一次机会异常来完善一下其中的代码:

using System;
using System.IO;
using System.Runtime.ExceptionServices;

namespace Walterlv.Demo.DoubiBlogs
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            AppDomain.CurrentDomain.FirstChanceException += OnFirstChanceException;

            try
            {
                File.ReadAllText(@"C:\walterlv\逗比博客\不存在的文件.txt");
            }
            catch (IOException)
            {
                Console.WriteLine("出现了异常");
            }
        }

        private static void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
        {
            // 现在,我们使用 Debugger.Break() 来中断程序。
            Debugger.Break();
        }
    }
}

保持 Visual Studio 异常设置窗格中的异常设置处于默认状态(意味着被 catch 的异常不会在 Visual Studio 中中断)。

现在运行这个程序,你会发现程序发生了中断,在我们写下了 Debugger.Break() 的那段代码上。

.NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)

而在这个时候查看 Visual Studio 中程序的堆栈,可以发现其实调用堆栈是接在一开始发生异常的那一个方法的后面的,而且是除了非托管代码之外帧都是相邻的。

.NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)

双击 Visual Studio 堆栈中亮色的帧,即可定位到我们自己写的代码。因此,双击第一个亮色的帧可以转到我们自己写的代码中第一个引发异常的代码块。这个时候可以查看应用程序中各处的状态,这正好是发生此熠时的状态(而不是 catch 之后的状态)。

优化代码和提示

为了让这段代码包装得更加“魔性”,我们可以对第一次机会异常的事件加以处理。现在,我们这么写:

[DebuggerStepThrough, DebuggerNonUserCode]
private static void OnFirstChanceException(object sender, FirstChanceExceptionEventArgs e)
    => ExceptionDebugger.Break();

用到的 ExceptionDebugger 类型如下:

using System.Diagnostics;

namespace Walterlv.Demo.DoubiBlogs
{
    internal class ExceptionDebugger
    {
        // 现在请查看 Visual Studio 中的堆栈以迅速定位刚刚发生异常时的程序状态。
        // 如果你按下 F10,可以立刻但不跳转到你第一个出现异常的代码块中。
        private static void BreakCore() => Debugger.Break();




        // 现在请查看 Visual Studio 中的堆栈以迅速定位刚刚发生异常时的程序状态。
        // 如果你按下 F10,可以立刻但不跳转到你第一个出现异常的代码块中。
        private static void LaunchCore() => Debugger.Launch();




        [DebuggerStepThrough, DebuggerNonUserCode]
        internal static void Break()
        {
            if (Debugger.IsAttached)
            {
                BreakCore();
            }
            else
            {
                LaunchCore();
            }
        }
    }
}

现在,发生了第一次机会异常的时候,会断点在我们写的 BreakCore 方法上。这里的代码很少,因此开发者看到这里的时候可以很容易地注意到上面的注释以了解到如何操作。

.NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)

现在再看堆栈,依然像前面一样,找到第一个亮色的帧可以找到第一个抛出异常的我们的代码。

.NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)

注意,我们在从第一次机会异常到后面中断的代码中,都设置了这两个特性:

  • DebuggerStepThrough 设置此属性可以让断点不会出现在写的这几个方法中
    • 于是,当你按下 F10 的时候,会跳过所有标记了此特性的方法,这可以直接跳转到最终发生异常的那段代码中去。
  • DebuggerNonUserCode 设置此代码非用户编写的代码
    • 于是,在 Visual Studio 的堆栈中,我们会发现这几个方法会变成暗色的,Visual Studio 不会优先显式这部分的源代码,这可以让错误在最关键的代码中显示而不会被我们刚刚写的这些代码中污染。

附加调试器

前面的代码中,我们做了一个判断 Debugger.IsAttached 。这是在判断,如果当前没有附加调试器,那么就附加一个。

于是这段代码可以运行在非 Visual Studio 的环境中,当出现了异常的时候,还可以补救选择一个调试器。

.NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)

当然,实际上附加到 Visual Studio 进行调试也是最佳的方法。只不过,我们不需要一定通过 Visual Studio,我们可以在一般测试代码的时候也能获得出现特定异常时立刻开始断点调查异常的特性。

.NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

C++沉思录

C++沉思录

Andrew Koenig、Barbara Moo / 黄晓春、孟岩(审校) / 人民邮电出版社 / 2008-1 / 55.00元

《C++沉思录》基于作者在知名技术杂志发表的技术文章、世界各地发表的演讲以及斯坦福大学的课程讲义整理、写作而成,融聚了作者10多年C++程序生涯的真知灼见。全书分为6篇32章,分别对C++语言的历史和特点、类和继承、STL与泛型编程、库的设计等几大技术话题进行了详细而深入的讨论,细微之处几乎涵盖了C++所有的设计思想和技术细节。全书通过精心挑选的实例,向读者传达先进的程序设计的方法和理念。一起来看看 《C++沉思录》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试