Подтвердить что ты не робот

Есть ли способ предотвратить использование Visual Studio исключений в определенном методе?

Я знаю, что могу управлять тем, как Visual Studio обрабатывает исключения в соответствии с их типом и тем фактом, что они в конечном итоге попадают в диалоговое окно "Исключение".

Однако у меня есть библиотека, которая внутренне бросает (и ловит) исключение ArgumentOutOfRange при вызове определенного метода. Исключение выбрано (и поймано библиотекой), возможно, в 1% случаев, но я очень часто называю этот метод. Редактор говорит это по дизайну (и действительно, дизайн, который они выбрали, имеет смысл).

Дело в том, что я не хочу, чтобы Visual Studio прерывалась каждый раз, когда генерируется исключение.

  • Я не хочу прерывать исключения ArgumentOutOfRange, поскольку у меня могут быть некоторые в моем коде и вы хотите сломать их.
  • Я не хочу включать отладку "только моего кода", потому что меня беспокоят исключения, выброшенные за пределы моего кода (особенно по соображениям производительности).

Есть ли способ достичь этого? Я искал атрибуты (например, DebuggerStepThrough), но пока не нашел что-то адекватное.

Любые подсказки о том, как это сделать?

4b9b3361

Ответ 1

Я думаю, что это невозможно в визуальной студии, но это, безусловно, в 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, вы можете загружать и использовать DLL-расширения DLL файлов WinDbg, напрямую предоставляя функциональные возможности (включая, возможно, тот, который вам нужен), но я еще не пробовал это - см., например, http://www.dotnetcurry.com/ShowArticle.aspx?ID=648

Ответ 2

Я не хочу включать отладку "только мой код"

Да, остановись прямо сейчас. Это именно то, что вам нужно, чтобы не получить нежелательные отладки. Если вы не хотите знать кого-то другого дерьмового кода, верните этот флажок.

Это всегда отключается от рельсов, когда программисты используют исключения для управления потоком. Очень распространенное преступление. Требуется два из них, чтобы превратить это в беспорядок, который превращает сессию отладки в очень утомительный кошмар щелчка. Когда вам нужна функция отладчика, которая разбивается на исключение первого шанса, вы в основном теряетесь, если кому-то еще это нужно.

Все надеются, что они смогут магически использовать атрибуты [DebuggerNonUserCode] или [DebuggerHidden] или [DebuggerStepThrough], чтобы эта проблема исчезла. Это не так. Другой программист не думал, что его код был неважным, чтобы заслужить эти атрибуты. И, ну, это было не потому, что в коде всегда есть ошибка, в которой используется код try/catch-em-all. Код покемонов.

Итак, Microsoft пришлось найти другой способ помочь программистам справиться с дрянным библиотечным кодом. Они сделали. Отметьте этот флажок, bam, решите. В любом случае, вы ничего не можете сделать с этим дрянным кодом, кроме отправки отвратительного графа автору. Не позволяйте нам или Microsoft замедлять вас, делая это, а вам нужно, чтобы создать продукт, который нравится людям.

Ответ 3

Что вы можете сделать, это использовать Concord, отладочный движок, который поставляется с Visual Studio (начиная с версии 2012). Он довольно расширяемый благодаря хорошо управляемому API (и развертывается с использованием технологии vsix), но он не полностью документирован.

У Concord есть концепция отладочных мониторов, которые мы можем использовать с помощью Интерфейс IDkmDebugMonitorExceptionNotification

Замечательно, что этот интерфейс может контролировать все выброшенные исключения. Он также может "подавлять" любое обнаруженное событие исключения, которое именно то, что нам нужно.

Я предлагаю начать с примера 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 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.

Примечание: как вы можете видеть, есть некоторые обман, чтобы убедиться, что программа завершится нормально.