【问题标题】:Is there a way to prevent Visual Studio from breaking on exceptions in a specific method?有没有办法防止 Visual Studio 打破特定方法中的异常?
【发布时间】:2011-07-06 09:06:13
【问题描述】:

我知道我可以根据异常类型以及最终使用“异常”对话框捕获异常这一事实来控制 Visual Studio 处理异常的方式。

但是,当我调用特定方法时,我有一个库在内部抛出(并捕获)ArgumentOutOfRange 异常。可能有 1% 的时间抛出异常(并被库捕获),但我经常调用这个方法。编辑说这是设计使然(事实上,他们选择的设计是有道理的)。

问题是我不希望 Visual Studio 在每次抛出异常时都中断。

  • 我不想停止处理 ArgumentOutOfRange 异常,因为我的代码中可能有一些异常并且想要处理这些异常。
  • 我不想启用“仅我的代码”调试,因为我担心在我的代码之外抛出异常(特别是出于性能原因)

有没有办法做到这一点?我一直在研究属性(例如DebuggerStepThrough),但还没有找到合适的东西。

关于如何做到这一点的任何提示?

【问题讨论】:

标签: visual-studio visual-studio-2010 debugging exception visual-studio-debugging


【解决方案1】:

我不想启用“只是我的代码”调试

是的,现在就停在那里。这正是您需要的功能,不会让不需要的调试器中断。如果您不想知道其他人的蹩脚代码,请重新打开该复选框。

当程序员使用异常进行流控制时,这总是会出轨。很常见的犯罪。需要 两个 才能将其变成一团糟,从而将调试会话变成非常乏味的点击噩梦。当您需要在第一次机会异常时中断的调试器功能时,如果其他人也需要它,您基本上就输了。

每个人都希望他们可以神奇地使用 [DebuggerNonUserCode] 或 [DebuggerHidden] 或 [DebuggerStepThrough] 属性来解决这个问题。它没有。另一位程序员认为他的代码并不重要,不值得拥有这些属性。而且,这并不是因为使用 try/catch-em-all 代码的代码中总是隐藏着一个错误。宝可梦代码。

因此微软不得不寻找另一种方法来帮助程序员处理糟糕的库代码。他们做到了。勾选那个复选框,bam,解决了。无论如何,除了向作者发送一个 nasty-gram 之外,您对那些糟糕的代码无能为力。也不要让我们或 Microsoft 拖慢您的步伐,你们都必须相处才能创造出人们喜欢使用的产品。

【讨论】:

  • 也许我的观点没有说清楚。该案例不是试图掩盖异常,而是使 Visual Studio 调试器默认行为合理而无需更改配置。这是一个例子。我们有一个带有自定义日志记录的应用程序,解决方案中另一个项目中的自定义日志记录的一部分具有将日志记录数据发布到 HTTP 端点的代码。 HTTP API 在失败时会抛出异常,这没关系,我们用 Polly 包装它来处理这些并重试,但是因为我们拥有这段代码,Visual Studio 每次都会在该行中断!在这种情况下,我们确实处理了异常。
  • 在这种情况下,由于 Visual Studio 中的间歇性故障和对已处理异常的干扰,团队中的开发人员将继续注释掉日志记录代码。
  • 不知道你在说什么。波莉?为什么调试器在处理时会停止?我回答了问的问题,似乎与您的问题无关。考虑发布您自己的问题,在此问题下发表评论以链接它。
  • @HansPassant Polly github.com/App-vNext/Polly 是一个异常和瞬态故障处理库,由 Dot Net Foundation 管理:dotnetfoundation.org/blog/welcome-polly
【解决方案2】:

我认为这在 Visual Studio 中是不可能的,但它肯定在 WinDbg 中。 参见例如http://blogs.msdn.com/b/alejacma/archive/2009/08/24/managed-debugging-with-windbg-breaking-on-an-exception-part-1.aspx

附带说明一下,从 Visual Studio 2010 开始,您似乎可以加载和使用 WinDbg 扩展 DLL,直接提供附加功能(可能包括您需要的功能),但我还没有尝试过 - 例如参见 @987654322 @

【讨论】:

    【解决方案3】:

    您可以使用 Concord,这是 Visual Studio 附带的调试引擎(从 2012 版开始)。它可以通过一个很好的托管 API 进行扩展(并且可以使用 vsix 技术进行部署),但它没有完整的文档记录。

    Concord 有调试监视器的概念,我们可以使用 IDkmDebugMonitorExceptionNotification Interface 挂钩

    很酷的是这个接口可以监控所有的异常抛出。它还可以“抑制”任何检测到的异常事件,这正是我们所需要的。

    我的建议是从 Hello World 示例开始: 。下载它,并确保它按预期运行。

    现在,只需像这样修改HelloWorld.vsdconfigxml

    <!--TODO: If you copy the sample, ensure to regenerate the GUID in this file -->
    
    <!-- 1. change component level to something higher than 40500 -->
    <ManagedComponent
      ComponentId="51736b11-9fb4-4b6d-8aca-a10a2b7ae768"
      ComponentLevel="40501"
      AssemblyName="HelloWorld">
    
      <!-- 2. change class full name to HelloWorld.ExceptionHandler, for example -->
      <Class Name="HelloWorld.ExceptionHandler">
        <Implements>
          <InterfaceGroup>
            <NoFilter/>
            <!-- 3. change supported interface -->
            <Interface Name="IDkmDebugMonitorExceptionNotification"/>
          </InterfaceGroup>
        </Implements>
      </Class>
    
    </ManagedComponent>
    

    然后,只需创建一个 ExceptionHandler.cs 类并在其中放入类似的内容:

    public class ExceptionHandler : IDkmDebugMonitorExceptionNotification
    {
        private bool _unhandledDetected;
    
        // we're being called!
        public void OnDebugMonitorException(DkmExceptionInformation exception, DkmWorkList workList, DkmEventDescriptorS eventDescriptor)
        {
            if (_unhandledDetected)
            {
                // this will cause the program to terminate
                eventDescriptor.Suppress();
                return;
            }
    
            if (exception.ProcessingStage.HasFlag(DkmExceptionProcessingStage.Unhandled))
            {
                _unhandledDetected = true;
            }
            else if (exception.ProcessingStage.HasFlag(DkmExceptionProcessingStage.Thrown))
            {
                if (SuppressException(exception))
                {
                    eventDescriptor.Suppress();
                }
            }
        }
    
        // should we suppress a thrown (1st chance) exception?
        private bool SuppressException(DkmExceptionInformation exception)
        {
            // implement any custom logic in here, for example use the exception's name
            if (exception.Name == typeof(ArgumentOutOfRangeException).FullName)
            {
                // for example, use the module (assembly) name
                var clrAddress = (DkmClrInstructionAddress)exception.InstructionAddress;
                var clrModule = clrAddress.ModuleInstance;
                if (clrModule.Name == "TheUglyOne.dll")
                    return true; // we don't want this one!
            }
            return false;
        }
    }
    

    当您运行项目时,您应该会看到 所有 异常被监控(无论您的“只是我的代码”和/或异常触发器设置如何),所以您只需要实现一些逻辑来压制你真的不想看到的那些。我没有检查过,但我想您可以使用自定义属性来构建您的逻辑,因为 Dkm 类提供了相当多的 .NET 元数据信息。

    注意:如您所见,有一些技巧可以确保程序正常终止。

    【讨论】:

      猜你喜欢
      • 2011-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-15
      • 1970-01-01
      相关资源
      最近更新 更多