В результате изучения этого вопроса: Rethrowing exception in Task doesn't make the Task to go to faulted state, я заметил очень странное поведение с ThreadAbortException
, о котором я не могу понять.Нечеткое поведение: Захват ThreadAbortException и исключение различного исключения
Теперь я знаю, что ThreadAbortException
- это особый вид исключения для начала. И documentation довольно четкое представление о том, что, когда он говорит:
ThreadAbortException
является исключением, которое может быть пойман, но он автоматически будет вновь поднят в концеcatch
блока.
Сценарий № 1: Документированное поведение.
static void Main(string[] args)
{
try
{
Thread.CurrentThread.Abort();
}
catch (Exception tae)
{
Console.WriteLine("caught exception: " + tae.GetType().Name);
}
Console.WriteLine("will never be reached");
}
Как и ожидалось, ThreadAbortException
будет вызваны повторно автоматически, в результате чего следующий вывод:
caught exception: ThreadAbortException
Сценарий № 2: Где он получает интересное, когда я решил бросить другое исключение в catch
блок:
static void Main(string[] args)
{
try
{
Thread.CurrentThread.Abort();
}
catch (Exception tae)
{
Console.WriteLine("caught exception: " + tae.GetType().Name);
throw new ApplicationException(); // will ThreadAbortException take precedence?
}
Console.WriteLine("will never be reached");
}
В этом случае, я предположил, что, несмотря на метания ApplicationException
, что в любом случае будет восстановлено значение ThreadAbortException
, чтобы гарантировать, что документальное поведение было сохранено. К моему удивлению, это выход, который привел:
caught exception: ThreadAbortException
Unhandled Exception: System.ApplicationException: Error in the application.
at ConsoleApplication1.Program.Main(String[] args) in C:\projects\ConsoleApplication1\Program.cs:line 193
ли ApplicationException
фактически заменить и предотвратитьThreadAbortException
от броска?!?
Сценарий № 3: И, наконец, чтобы сделать дела более интересными, я обернуть обработки моего существующего исключения с еще одним слоем try-catch
:
static void Main(string[] args)
{
try
{
try
{
Thread.CurrentThread.Abort();
}
catch (Exception tae)
{
Console.WriteLine("caught exception: " + tae.GetType().Name);
throw new ApplicationException();
}
}
catch (Exception outerEx)
{
Console.WriteLine("caught outer exception: " + outerEx.GetType().Name);
}
Console.WriteLine("will never be reached");
}
Теперь я не слишком уверен, что ожидать. Какое исключение будет обнаружено во внешнем блоке catch
? Будет ли это ApplicationException
? И если да, значит ли это, что я смогу проглотить исключение и действительно удастся распечатать строку will never be reached
?
Это фактический выход:
caught exception: ThreadAbortException
caught outer exception: ApplicationException
Из вышеприведенного вывода, это выглядит как внешний catch
блок на самом деле поймать ApplicationException
. Но к концу , чтоcatch
блок, ThreadAbortException
теперь внезапно появляется из воздуха и возвращается?
Вопрос (и): Может ли кто-нибудь объяснить и согласовать сценарии № 2 и № 3? Как это происходит в сценарии №2, похоже, что ThreadAbortException
неожиданно заменен другим исключением? Тем не менее, в сценарии № 3, похоже, что ThreadAbortException
все еще был там? Как это происходит?Это где-то документировано?
Еще более заинтересован в подключении к событию «AppDomain.UnhandledException» - он срабатывает, даже если вы обрабатываете его, как и следовало ожидать, но в противном случае вы не получите поведение по умолчанию. – jdphenix
https://gist.github.com/jdphenix/32a710ad5def12cf121c - Запустите это, наглядно демонстрируя, что 'ThreadAbortException' продолжает распространяться. У меня нет объяснений, почему обработчик исключенных по умолчанию по умолчанию не захватывает его. – jdphenix
@jdphenix: попробуйте прокомментировать «try-catch» в вашем методе 'HandleApplicationException (Action action)' и посмотреть, какое исключение попало в обработчик события AppDomain.UnhandledException. Обратите внимание, что в этом случае похоже, что «ThreadAbortException» не распространялся, а вместо этого «ApplicationException» распространяется. Очень странно. – sstan