Причина дизайна why.NET не имеет концептуального (фатального)типа исключения ошибок? [закрытый]


Предварительное Примечание:

Этот вопрос не предназначен для того, чтобы колотить по .NET, и не предназначен для ведения дискуссионной войны, если есть такая вещь, как "фатальное исключение" - разработчики Java явно думали, что есть, разработчики .NET либо думали иначе, не знали иначе, или может быть другая (техническая) причина, по которой иерархия исключений такова, как она есть.

Меня больше всего интересует, есть ли проектный документ или заявление любого из MS проектировщики, почему иерархия .NET такова, как она есть сегодня. Дикие догадки и предположения дадут плохие ответы. Связные аргументы / примеры, почему нет такой вещи, как (Категоризуемое) фатальное исключение , безусловно, могут дать правильные ответы, хотя я вынужден с ними не согласиться.но, в отличие от комментариев, я обещаю не спорить с любым связным ответом ; -) другая категория ответов может показать доказательства того, что классификация типов Java Error - плохая идея / не работает на практике в Java, тем самым неявно показывая, почему .NET это не нужно. :- )


Работая над тем, чтобы стать более опытным программистом C#, я заметил кое-что, что я считаю довольно странным (*) в иерархии исключений .NET :

Базовый класс для всех брошенных типов является Exception (Ну, в принципе, так или иначе ).

В частности, многие исключения непосредственно вытекают из Exception и чем дальше, тем лучше. категоризация в SystemException -> и т. д. кажется довольно бессмысленным немного произвольным.

В качестве примера, особенно странным мне кажется, что SEHException is-a ExternalExpection is-a SystemException, когда это действительно было бы больше похоже на ошибку типа аварии и ожога.

Хотя я не слишком опытен в Java, я нахожу различие, которое Java делает wrt. тот самый Error Тип против "нормального" Exception, чтобы иметь много смысла. Детали, конечно, можно оспорить, но .NET / C# даже не пробовать такой подход кажется странным.

У Эрика Липперта из C# fame естьхорошая статья о классификации исключений , с которой я в основном согласен и которая заставляет меня еще больше удивляться, почему .NET даже не пытается предоставить ведро для "фатальных исключений".


Под "фатальным исключением" я в основном подразумеваю ту же самую концепцию, которую описывает Мистер Липперт:]}

Фатальные исключения-не ваша вина, вы не можете предотвратить их, и вы не может разумно убирать от них. ...

Примечание: самое главное, что они, вероятно, и конкретно также не ошибка операции, которую вы вызвали, что вызвало исключение.

... Они почти всегда случаются, потому что этот процесс глубоко болен и вот-вот выйдет из своего состояния. страдание. Из памяти, прерванная нить и так далее. Есть абсолютно нет смысла ловить их, потому что ничего не может сделать ваш ничтожный пользовательский код исправит проблему. Просто позволь своему " наконец-то" блоки бегут и надеются на лучший. (Или, если вы действительно беспокоитесь, потерпите неудачу быстро и не позволяйте наконец блоки работают; в этот момент они могут только ухудшить ситуацию. Но это тема для другого дня.)

Я замечу, что это совершенно нормально для некоторого набора фатальных исключений технически быть таким же, как и любое другое исключение. Вы должны очень хорошо уметь ловить его в соответствующее время - просто для 99% кода это не подходит для обработки этих в все. Возьмем примеры Мистера Липпертса: скажем, я вызываю функцию, чтобы открыть файл, который может вызывать различные исключения. Если я поймаю что-нибудь из этого, все, что я хочу сделать, это сообщить, что открытие файла не удалось по причине X и продолжить соответствующим образом. однако Если открытие файла вызывает, скажем, ThreadAbortedException, не имеет смысла сообщать что-либо, поскольку не операция открытия файла завершилась неудачей, но какой-то код прервал текущий поток и обработал его в той же точке, что и гипотетический FileNotFoundException не имеет смысла в подавляющем большинстве случаев.

Комментаторы, похоже, думают, что только сайт catch действительно может судить, является ли что-то "фатальным" и никакая предварительная классификация не подходит, однако я бы сильно подозревал, что существует хороший список исключений , что 99% пользовательского кода никогда не хочет поймать :

Взять StackOverflowException (и я уверен, что есть еще), который является" просто " регулярным SystemException то есть запрограммировано быть фатальным :

В .NET Framework 1.0 и 1.1 вы можете поймать StackOverflowException объект (например, для восстановления из unbounded рекурсия). Начиная с .NET Framework 2.0, вы не можете поймать StackOverflowException объект с блоком try / catch, и соответствующий процесс завершается по умолчанию.

Обратите внимание, что я не думаю, что фатальное исключение должно немедленно завершить приложение (on противоположность). Все, что я спрашиваю, - Это почему .NET framework не пытается представить "фатальность" в иерархии исключений, когда дизайнеры явно считают некоторые исключения более фатальными, чем другие.


(*) "рассмотрим довольно странно" на самом деле означает, что я лично, в этот самый момент во временном континууме, нахожу иерархию исключений .NET полностью испорченной.

1 3

1 ответ:

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

Тем не менее, я могу сделать здесь несколько замечаний. Я думаю, что это разумное предположение, что все вовлеченные сожалеют о существовании SystemException и ApplicationException. В то время казалось хорошей идеей разделить исключения на две широкие категории: исключения, созданные самой "системой", и исключения, созданные пользователями системы. Но на практике это не является полезным различением, потому что то, что вы делаете с исключениями,-это перехват их, и при каких обстоятельствах вы хотите перехват либо (1) всех пользовательских исключений, либо (2) всех системных исключений? Никакие обстоятельства не приходят на ум.

Что это иллюстрацией здесь является не столько провал дизайна в конкретном случае - хотя, конечно, дизайн не велик - а скорее то, что при одинарном наследовании ООП вы получаете только один выстрел по "оси наследования", как это часто называют в Microsoft, и плохое решение может держаться с вами в течение длительного времени.

Теперь очень легко сказать, что в ретроспективе нам, возможно, следовало бы использовать какой-то другой поворот. Вы заметили, что в моей статье я классифицирую исключения в соответствии с тем, как они должны быть пойманы -- фатальные исключения не ловятся, потому что их ловить бесполезно, тупоголовые исключения не ловятся, потому что они на самом деле являются средствами отладки, досадные исключения должны быть пойманы из-за плохого дизайна API, а экзогенные исключения должны быть пойманы, потому что они указывают на то, что мир отличается от того, на что вы надеялись. Похоже, что здесь есть возможность лучшего поворота, где тип исключения указывает, является ли он фатальным или нет, и указывает, должен ли он быть поймали или нет. Это, конечно, не единственный возможный поворот, но он кажется правдоподобным. Можно создать статический анализатор (либо в компиляторе, либо в стороннем средстве), который проверяет правильность перехвата исключения.

Это кажется особенно правдоподобным, потому что, конечно, есть некоторые исключения в .NET, которые являются фактически супер-пупер-фатальными. Вы можете поймать переполнение стека или прерывание потока, но система агрессивно реагирует на их повторное выбрасывание. Было бы неплохо, если бы это было так. они каким-то образом попали в метаданные.

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

Например, почему нам нужно, чтобы фатальные исключения былиисключениями ? Если это действительно так, что некоторые исключения фатальны, и это действительно так, что в некоторых редких, но критических сценариях вам нужен код для запуска, даже когда программа идет вниз из-за фатального исключения, то этот сценарий может подняться до уровня, где вы хотите синтаксис в языке, чтобы захватить эти семантики. Скажем, блок try-fatality, где код очистки только выполняется в чрезвычайно маловероятном случае фатальной ошибки. Может быть, это хорошая идея, а может быть, и нет, но суть в том, что это идея о том, чтобы поместить функцию в язык для решения проблемы , а не накапливать все больше и больше семантики на механизм, который кажется возможно, не идеально подходит для всех целей, которые он использует. Например, почему вообще существуют" тупоголовые " исключения? Существование тупоголовых исключений, таких как "эта ссылка не может быть null, вы пустышка" или "вы пытались записать файл после его закрытия, вы пустышка", на самом деле являются только исключениями, потому что они являются недостатками, в первом случае системы типов и во втором случае дизайна API. В идеале не было бы никаких тупоголовых исключений, потому что это было бы просто невозможно представить плохую программу на языке в первую очередь. Такие механизмы, как контракты кода, могут быть встроены в язык, чтобы гарантировать, что "тупоголовая" ситуация исключения будет поймана во время компиляции. Опять же, может быть, это хорошая идея, а может быть, и нет, но суть в том, что есть возможность решить эту проблему на уровне языкового дизайна, а не делать исключения нести это бремя, а затем спрашивать, как спроектировать иерархию типов, которая представляет собой тупоголовое исключение явно.