跳过第一次机会例外

Posted

技术标签:

【中文标题】跳过第一次机会例外【英文标题】:Skip first chance exceptions 【发布时间】:2014-03-10 15:35:23 【问题描述】:

我继承了一个项目,当它在调试中启动时,会在 8-10k NotImplementedExceptions 的某个地方抛出。正因为如此,应用程序在调试时需要一分钟多的时间才能启动......每个。单身的。时间。

我与该项目的原始开发人员进行了交谈,他们对该问题的解决方案是“只需按 Ctrl+F5 即可启动,无需附加调试器”。除了这是开发史上最糟糕的问题解决方案之一之外,它确实有效并且应用程序立即启动。我正在尝试学习这个新的代码库,所以跳过调试器对我来说不是一个选择。

显然,我知道任何应用程序都不应该以 10,000 个异常开始,但在我开始修复之前,我必须能够调试程序。

我想抑制或跳过第一次机会异常,就像在没有附加调试器的情况下启动一样。我查看了this thread 并将[DebuggerNonUserCode] 属性应用于相关方法,但它只阻止了将异常写入输出窗口。该程序仍然需要一分钟多的时间才能启动。这可能吗?

编辑:

我忘了提一下,我没有在 Debug->Exceptions 窗口中检查任何内容。此外,所有异常都包含在Try.. Catch 语句中

【问题讨论】:

应用启动后附加调试器的实际问题是什么? 右键单击输出窗口,取消勾选“异常消息”。这会有所帮助,强烈建议真正治愈。 我需要在应用程序启动时调试/观察正在执行的代码。这是抛出异常的地方。本质上:在表单显示之前,会引发 10k 异常。 出于好奇,这些未实现的方法是如何被调用的,随后又是如何捕获异常的呢? NotImpl 主要用于在开发过程中排除新功能,或者传递给调用客户端以表明某些功能确实不可用。 NotSupportedException 就是出于这个原因而创建的,尽管我怀疑它不会对您的问题有任何改变,只是想指出这一点。 【参考方案1】:
    在调试 -> 异常 -> 公共语言运行时异常 -> 系统 -> System.NotImplementedException 下检查您的 Visual Studio 设置,并确保未选中抛出。 (默认情况下不应该检查它,但这会导致它停止,即使要处理异常)。

    糟糕的解决方法:在超出所有异常的代码部分中,您要开始调试,输入以下行

    System.Diagnostics.Debugger.Launch();
    System.Diagnostics.Debugger.Break();
    

然后您可以启动 Ctrl+F5,然后当它到达代码中的那个点时,系统会提示您附加调试器。

【讨论】:

难以置信...您的蹩脚解决方法正是我真正想要的。我能够在开始执行后和异常抛出行之后立即启动调试器。某些对象的某些属性不能正确产生结果,但我可以处理。太棒了。 @Brandon 顺便说一句,.Launch.Break 可能就足够了(即只是其中之一),但我记不清了,所以我把两者都放了。如果调试导致您在此处中断两次,您可以删除其中一次。 是的,我确实注意到了这一点,只是使用了.Launch。谢谢! 然后我得到 System is not defined. @user2568374,如果你得到System 未定义,那么VS/.NET 安装有问题。在 System 命名空间中引用其他内容怎么样?【参考方案2】:

编辑:进行重大编辑以消除我清晨的脑损伤。

为我的观点提供一些额外的信息,尝试显示可用于减少此数量异常的启动时间的步骤。此代码允许我分析 N 次调用,无论是否抛出异常:

void Run(int n, bool doThrow, bool doExcept)

    for (int i = 0; i < n; i++)
    
        if (doExcept)
        
            try
            
                if (doThrow)
                    throw new NotImplementedException();
            
            catch (NotImplementedException)
            
            
        
    

在 VS 托管进程的调试模式下,在“异常”对话框中未设置复选标记时,测试场景会给出以下数字。

1; 4.000 msec
1: 0.000 msec (no throw)
1: 0.000 msec (no throw, no except)
10; 32.000 msec
10: 0.000 msec (no throw)
10: 0.000 msec (no throw, no except)
100; 780.000 msec
100: 0.000 msec (no throw)
100: 0.000 msec (no throw, no except)
1000; 7251.000 msec
1000: 0.000 msec (no throw)
1000: 0.000 msec (no throw, no except)
10000; 35694.000 msec
10000: 0.000 msec (no throw)
10000: 0.000 msec (no throw, no except)

很明显,例外的数量在这里很重要,正如您所期望的那样。我将在一分钟内使用来自不同场景的更多数字进行编辑。

在使用 VS 托管进程进行调试时,异常大约需要 3.5-7 毫秒。在调试模式下禁用 VS 托管进程(仍然允许调试)会将每个异常的时间缩短到 1.9 毫秒:

1; 3.000 msec
10; 21.000 msec
100; 198.000 msec
1000; 1917.000 msec
10000; 19065.000 msec

没有 VS 托管过程的发布模式大约需要 1.8 毫秒(插入我的笔记本电脑后编辑):

1; 3.000 msec
10; 17.000 msec
100; 184.000 msec
1000; 1823.000 msec
10000; 18248.000 msec

并且在调试器之外以发布模式运行每个异常大约需要 0.016 毫秒:

1; 1.000 msec
10; 1.000 msec
100; 3.000 msec
1000; 19.000 msec
10000; 138.000 msec

所以在我的测试设置中,它仍然不会从调试器“立即”加载,发布时有 10k 异常。不过,这可能与我之前在 2010 年安装时遇到的问题有关(我已经重新安装了)。它在调试器之外加载速度非常快。

这是我的完整测试台:

static void Main(string[] args)

    Stopwatch sw = new Stopwatch();
    var p = new Program();

    int[] tests = new int[]  1, 10, 100, 1000, 10000 ;
    foreach (int n in tests) 
        sw.Start();
        p.Run( n, true, true);
        sw.Stop();
        Console.WriteLine(string.Format("0; 1:0.000 msec", n, sw.ElapsedMilliseconds));

        sw.Start();
        p.Run(n, false, true);
        sw.Stop();
        Console.WriteLine(string.Format("0: 1:0.000 msec (no throw)", n, sw.ElapsedMilliseconds));

        sw.Start();
        p.Run(n, false, false);
        sw.Stop();
        Console.WriteLine(string.Format("0: 1:0.000 msec (no throw, no except)", n, sw.ElapsedMilliseconds));
    

    Console.WriteLine("Any key to exit...");
    Console.ReadKey();

【讨论】:

哦,废话。没关系。糟糕的是,我没有重置计时器。 嗯,就是这样,不附加调试器会使应用程序立即启动。 使用来自测试台的实数进行编辑。 希望这将为您提供一个很好的测试平台,帮助您找出最佳情况(发布模式、无 vs 托管等),而不会产生实际应用程序调用的开销。

以上是关于跳过第一次机会例外的主要内容,如果未能解决你的问题,请参考以下文章

第一次机会例外

“第一次机会例外......”消息中的十六进制数字是啥意思?

小米还有最后一次机会翻身

从入坑计算机到成为程序员

Visual Studio 2015:调试器不会跳过

给错过,一次重来的机会|Flutter Festival 直播回放来啦!