14

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

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

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

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

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

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

4

3 回答 3

3

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

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

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

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

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

于 2016-12-02T23:31:17.987 回答
2

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

附带说明一下,从 Visual Studio 2010 开始,您似乎可以加载和使用 WinDbg 扩展 DLL,直接提供附加功能(可能包括您需要的功能),但我还没有尝试过 - 例如参见http://www .dotnetcurry.com/ShowArticle.aspx?ID=648

于 2011-03-08T10:46:18.120 回答
1

What you can do is use Concord, the debug engine that ships with Visual Studio (starting with version 2012). It's quite extensible through a nice managed API (and deployable using vsix technology), but it's not fully documented.

Concord has the concept of debug monitors, that we can hook using the IDkmDebugMonitorExceptionNotification Interface

The cool thing is this interface can monitor all exceptions thrown. It can also "suppress" any detected exception event, which is exactly what we need.

What I suggest is to start with the Hello World sample: . Download it, and make sure it runs as expected for you.

Now, just modify HelloWorld.vsdconfigxml like this:

<!--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>

Then, just create an ExceptionHandler.cs class and put something like this in there:

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;
    }
}

When you run the project, you should see all exceptions being monitored (regardless of your 'just my code' and/or exception triggers settings), so what you just need to do is implement some logic to suppress the ones you really don't want to see. I've not checked but I suppose you could build your logic using custom attributes as the Dkm classes provide quite a lot of .NET metadata information.

Note: as you can see, there is some trickery to make sure the program will terminate normally.

于 2016-12-07T22:43:41.213 回答