Есть ли способ предотвратить использование Visual Studio исключений в определенном методе?
Я знаю, что могу управлять тем, как Visual Studio обрабатывает исключения в соответствии с их типом и тем фактом, что они в конечном итоге попадают в диалоговое окно "Исключение".
Однако у меня есть библиотека, которая внутренне бросает (и ловит) исключение ArgumentOutOfRange
при вызове определенного метода. Исключение выбрано (и поймано библиотекой), возможно, в 1% случаев, но я очень часто называю этот метод. Редактор говорит это по дизайну (и действительно, дизайн, который они выбрали, имеет смысл).
Дело в том, что я не хочу, чтобы Visual Studio прерывалась каждый раз, когда генерируется исключение.
- Я не хочу прерывать исключения
ArgumentOutOfRange
, поскольку у меня могут быть некоторые в моем коде и вы хотите сломать их.
- Я не хочу включать отладку "только моего кода", потому что меня беспокоят исключения, выброшенные за пределы моего кода (особенно по соображениям производительности).
Есть ли способ достичь этого? Я искал атрибуты (например, DebuggerStepThrough
), но пока не нашел что-то адекватное.
Любые подсказки о том, как это сделать?
Ответы
Ответ 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.
Примечание: как вы можете видеть, есть некоторые обман, чтобы убедиться, что программа завершится нормально.