Страницы

Поиск по вопросам

понедельник, 15 октября 2018 г.

Неожиданное поведение фильтров исключений

Искал информацию по фильтрам исключений в C# и наткнулся на эту статью. В статье описывается случай, когда происходит исключение непосредственно внутри фильтра исключений, например:
class Program { public static void Main() { TestExceptionFilters(); } public static void TestExceptionFilters() { try { throw new Exception("Original Exception"); } catch (Exception ex) when (MyCondition()) { Console.WriteLine(ex); } } public static bool MyCondition() { throw new Exception("Condition Exception"); } }
Со следующим комментарием к коду:
Таким образом, мы можем указать условие в фильтре исключений; catch-блок будет исполняться только в том случае, если условие выполнилось. И мы можем использовать bool-функцию в качестве условия. Но что произойдёт, если само условие выбросит исключение? Ожидаемым поведением является следующее: исключение игнорируется, условия считается ложным
Вот уж для меня действительно стало неожиданным, что ожидаемое поведение - это игнорирование исключения. Сразу не поверил, но компилятор ведет себя так, как и ожидают люди: игнорирует исключение в фильтре
Сам вопрос: как так произошло, что игнорировать исключения - это норма? А что если я захочу логгировать ошибку в фильтре (это одно из применений фильтров исключений), а у меня там будет ошибка (нет такого файла, например), то мало того, что я не увижу, что у меня есть ошибка, так еще и не зайду в нужный блок catch, так как "условие будет считаться ложным"


Ответ

Очень похоже что это не норма, а банальная необходимость. И вот почему: в .NET и C# в частности гарантируется выполнение блока finally, независимо от результатов работы кода в блоке try и наличия либо отсутствия обработки возникших исключений в блоках catch. Ваш код порождает исключение в потоке управления конструкции try ... catch ... finally. Если бы оно не было проигнорировано, это привело бы к прерыванию потока управления и невозможности выполнить блок finally. Но выполнение finally гарантировано спецификацией.
Получили явное противоречие. Простой выход из ситуации - игнорировать исключения в потоке управления конструкции try ... catch ... finally, для соблюдения спецификации.
Можно было бы пробросить полученное исключение на уровень выше, а в свойстве InnerException передать исходное исключение, из-за которого все и произошло, но от такого решения будет больше путаницы, чем пользы.
PS: упомянутый поток управления не имеет ни какого отношения к многопоточности

Непосредственно к вопросу не относится, но для общей картины нужно добавить, что есть ряд исключений, для которых не выполняются ни catch, ни finally. Как правило это исключения вызывающие падение домена приложения или самой CLR, причина которых может быть как серьезной внутренней ошибкой приложения (например StackOverflowException), так и внешними проблемами CLR или операционной системы (частный случай OutOf MemoryException).

Комментариев нет:

Отправить комментарий