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

Try-Catch-finally блокирует проблемы с .NET4.5.1

У меня есть простой блок кода try-catch-finally, который работает как ожидается в .NET3.5, но тот же код ведет себя совершенно по-другому в проекте, созданном с .NET4.5.1. В принципе, в .NET4.5.1 блок "finally" не попадает, если возникает исключение, которое не является поведением, которое я ожидал от блока try-catch-finally. Я пробовал на разных машинах, и у меня было еще 2 моих коллеги, и мы все получили тот же результат. Это беспокоит меня, потому что я использую блок finally для закрытия DataReaders, определенных подключений и еще чего-то.

.NET4.5.1 не попадает в блок "finally" , если исключение выбрано в режиме RELEASE без отладчика или при запуске файла RELEASE compiled EXE. В режиме отладки обе версии .NET попадают в блок "finally" .

Опять же, приведенный ниже код ведет себя так, как ожидалось, в режиме .NET3.5 RELEASE без отладчика, но не в .NET4.5.1. Я что-то упускаю? Может кто-нибудь помочь?

class Program
{
    static void Main(string[] args)
    {
        try
        {
            string a = null;
            var x = a.Length;
            Console.WriteLine(x);
        }
        catch (Exception ex)
        {
            throw;
        }
        finally
        {
            Console.WriteLine("This is the finally block.");
        }
        Console.WriteLine("You should not be here if an exception occured!");
    }
}
4b9b3361

Ответ 1

приведенный ниже код ведет себя как ожидалось в режиме .NET3.5 RELEASE без отладчика, но не в .NET4.5.1. Я что-то пропустил?

ПРИМЕЧАНИЕ. Я переоценил уровень undefined -ness этого поведения; спасибо комментатору Voo за указание на это. Я должен был вернуться к спецификации в первую очередь.

Да. CLR требуется по спецификации CLI для завершения программы, когда есть необработанное исключение. Требуется только запуск блоков finally, если обрабатывается исключение. Спецификация неясна в вопросе о том, требуется ли CLR, разрешено или запрещена выполнение блоков finally, когда есть необработанное исключение; безопасное предположение заключается в том, чтобы сказать, что это поведение undefined по спецификации, и это зависит от конкретной реализации.

CLR может выбрать запуск блоков finally для необработанных исключений или нет по своей прихоти. Многие люди считают, что CLR использует этот алгоритм: по исключению, подходите к стеку вызовов, выполняя, наконец, блоки, когда ищете, ищите обработчиков; если обработчик не найден, завершите процесс. CLR не требуется соответствовать этому алгоритму в программе с необработанным исключением. В частности, CLR разрешено определять черной магией, что нет обработчика исключений, и никогда не запускать никаких блоков finally. Независимо от того, решит ли он это сделать или нет в некоторых версиях CLR в некоторых случаях, я не знаю. Ни в коем случае нельзя полагаться на это поведение для правильности вашей программы, потому что программа с необработанным исключением неверна.

В спецификации также отмечается, что CLR может предложить предлагать начать отладчики или нет по своей прихоти. CLR не требуется делать то же самое в отладке или выпуске, и не требуется делать то же самое с версии на версию.

Проблема в том, что вы сформировали ожидание, основанное на прошлом опыте, но нет документации, в которой говорится, что прошлый опыт является основой для прогнозирования будущего. Скорее всего, наоборот; CLR разрешено изменять свое поведение на основе фазы луны, если она нравится, в программе, которая имеет необработанное исключение.

Если вы хотите, чтобы ваша программа вела себя предсказуемо, не бросайте необработанные исключения.

Итак, если я правильно вас понимаю, если есть еще один улов где-то вверх по течению, блок finally выполнит?

Нет, я этого не говорил. Пусть сломается.

Если в программе есть неперехваченное исключение, то поведение программы определяется реализацией. Каким бы ни было поведение, которое вы получили, и CLR находится в пределах своих прав на создание такого поведения. Это включает в себя как запуск блоков finally, так и запуск блоков finally.

Предположим, что нет неотображаемого исключения, и возникает исключение, и на пути к catch есть блок finally. Гарантируется ли выполнение блока finally? Нет. Есть много вещей, которые могут помешать окончательному блокированию от выполнения в юридической программе. Например, другой, наконец, блок или фильтр исключений по пути мог перейти в бесконечный цикл или быстрый сбой, любой из которых предотвратил бы выполнение блока finally. Если у вас АБСОЛЮТНО ПОЛОЖИТЕЛЬНО должен быть запущен какой-то код очистки, вам необходимо исследовать области ограничений. (Я не знаю, как они работают, мне никогда не приходилось учиться, я слышал, что они сложны.).

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

Я полагаю, что в случае действительно необработанного исключения программа должна прекратиться в любом случае, так что сиротское соединение/транзакция БД не должно быть проблемой?

Является ли это проблемой или нет, я не могу сказать. Попросите автора вашей базы данных.

Очень вероятно, что программа завершится, хотя снова я отмечаю, что CLR не требуется для такого поведения. Предположим, например, существует некоторая нить, которая продолжает работать, пока CLR пытается выяснить, установлен ли у вас отладчик или нет. CLR находится в пределах своих прав, чтобы занять какое-то время, чтобы понять это, и, следовательно, в пределах своих прав поддерживать этот поток. Делает это или нет, я не знаю. Я знаю, что я не хочу полагаться на любое поведение.

Кроме того, использование "AppDomain.CurrentDomain.UnhandledException" считается "обработкой"

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

Ответ 2

В дополнение к тому, что написал Lipper, обратите внимание, что он написан в MSDN... В попробуйте... наконец:

Однако, если исключение необработанно, выполнение блока finally зависит от того, как запускается операция исключения. Это, в свою очередь, зависит от того, как настроен ваш компьютер.

и

Обычно, когда необработанное исключение заканчивает приложение, независимо от того, выполняется ли блок finally, не важно.

а затем поясняется, что если вы положите try... catch на "высокий" уровень, тогда будет выполнен внутренний try... finally.

Ответ 3

До версии 4.0 необработанные исключения запустили "Microsoft.NET Error Reporting Shim", в котором показано диалоговое предложение "Отладка" или "Закрыть программу". Прокладка позволяет приложениям .NET закрывать "чисто".

Начиная с Framework 4.0 (насколько я могу судить) необработанные исключения приводят к тому, что Windows запускает отчет об ошибках Windows (WER), который появляется как отчет о проблемах с Windows в диспетчере задач. Это приложение показывает аналогичный диалог с прокладкой, но требует более жесткого подхода к убийству приложения, возможно, вызывая TerminateProcess или TerminateThread, который не позволит выполнять какой-либо дополнительный код в процессе неправильной работы.