Получение необработанного исключения в отладчике VS2010, даже если исключение обработано
У меня проблема с VS2010, когда отладчик останавливается с необработанным исключением. Тем не менее, исключение определенно обрабатывается. Фактически, если я добавлю код в блок catch, я нажму его, когда нажму F5. В "Отладке -> Исключения" у меня определенно не установлен флажок "Брошено", поэтому в IMO нет абсолютно никаких причин для всплывающего диалогового окна необработанных исключений...
Я не могу опубликовать точный код, но скоро буду работать над образцом. Основная идея раздела обидного кода состоит в том, что у меня есть поток, который общается с аппаратным обеспечением, и если у меня возникает ошибка при разговоре с ним, я выкидываю HardwareException
, Тема запускается с BeginInvoke
и исключение перехватывается в обработчике обратного вызова при вызове EndInvoke
,
Когда в отладчике выдается исключение, я получаю окно с сообщением "HardwareException не обрабатывается кодом пользователя". Но это так!!!
РЕДАКТИРОВАТЬ - Ну, это сводит меня с ума. У меня есть пример кода, который является представителем кода в моем приложении, и это выглядит так:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Remoting.Messaging;
using System.Threading;
namespace ConsoleApplication1
{
public class HardwareException : ApplicationException
{
public HardwareException( string message) : base(message) {}
}
class Program
{
delegate void HardwareTestDelegate();
static void Main(string[] args)
{
HardwareTestDelegate d = new HardwareTestDelegate( HardwareTestThread);
d.BeginInvoke( HardwareTestComplete, null);
while( true);
}
static void HardwareTestThread()
{
throw new HardwareException( "this is a test");
}
static void HardwareTestComplete( IAsyncResult iar)
{
try {
AsyncResult ar = (AsyncResult)iar;
HardwareTestDelegate caller = (HardwareTestDelegate)ar.AsyncDelegate;
caller.EndInvoke( iar);
} catch( Exception ex) {
Console.WriteLine( "Should see this line without getting an unhandled exception message in the IDE");
}
}
}
}
Я выбрасываю свое HardwareException из потока, а затем обрабатываю исключение при вызове EndInvoke. Я думаю, Мерфи был прав, потому что, когда я запускаю этот пример кода, он делает то, что я ожидаю - то есть в IDE не появляется сообщение об ошибке необработанного исключения!
2 ответа
Вот ответ от Microsoft, дело 111053102422121. Аллен Венг пишет следующее:
Анализ:
Для вашей информации, CLR повторно сгенерирует исключение внутри обратного вызова, когда вы вызываете EndInvoke(). Ниже приведена упрощенная версия EndInvoke():
public object EndInvoke(IAsyncResult asyncResult)
{
using (new MultithreadSafeCallScope())
{
ThreadMethodEntry entry = asyncResult as ThreadMethodEntry;
............
if (entry.exception != null)
{
throw entry.exception;
}
}
}
Исключение будет обрабатываться в функции обратного вызова или в асинхронном методе, если предоставляется обработчик исключения. Вот как это работает без отладчика.
Когда вы запускаете его в VS.NET, кажется, что отладчик проверяет только наличие обработчика исключений в асинхронном методе. Если такого обработчика нет, отладчик подумает, что исключение не обработано, и выдаст сообщение об ошибке, уведомляющее вас об этом.
Предложение:
Приложение должно работать как положено, когда вы запускаете его в одиночку. Если сообщение об ошибке раздражает вас при отладке, вы можете отключить его, сняв флажок "Необработанный пользователь" для "Исключения времени выполнения общего языка" в диалоговом окне "Исключения" ("Отладка | Исключения" или нажмите сочетание клавиш CTRL+ATL+E). Или вы можете добавить try/catch в асинхронный метод. В последнем случае исключение устанавливается равным нулю и не будет переброшено в EndInvoke().
У меня такая же проблема, поэтому я опубликую этот возможный обходной путь ради потомков:
В вашем коде, который выбрасывает исключение в код.NET (HardwareTestThread() в приведенном выше примере), поймайте выбрасываемое исключение и оберните его в некоторый эзотерический тип исключения.NET, для которого вы можете отключить опцию "необработанный пользователем" в диалоге Отладка> Исключения. В моем случае мне нужно было разрешить IOException распространяться через некоторый код.NET обратно в мой код, поэтому я просто перехватил IOException и поместил в исключение AppDomainUnloadedException, прежде чем позволить ему распространяться через код.NET обратно в мой блок catch. Я выбрал AppDomainUnloadedException, поскольку необработанный пользователь по умолчанию не отмечен для него и находится в сборке System.dll, поэтому он уже был импортирован в мой проект, хотя любое исключение должно работать, если вы отключите опцию "пользовательский необработанный" и вам все равно, что отладчик не будет нарушать этот тип исключения в будущем.
Вот мой код, который оборачивает IOException, которое мне нужно было распространять:
public override int Read(byte[] buffer, int offset, int count)
{
try { return innerStream.Read(buffer, offset, count); }
catch (IOException ex) { throw new AppDomainUnloadedException("Exception from innerStream: " + ex.Message, ex); }
}
И вот мой код, где я ловлю его на другой стороне.NET-кода, через который он должен был распространяться:
try { bytesRead = sslStream.Read(buffer, offset, count); }
catch (Exception ex) { /* ex handled here. */ }