Рассмотрим эту программу:Изменение необработанное исключение в перекачиваемой один в финальном блоке
using System;
static class Program {
static void Main(string[] args) {
try {
try { throw new A(); }
finally { throw new B(); }
}
catch (B) { }
Console.WriteLine("All done!");
}
}
class A : Exception { }
class B : Exception { }
Здесь исключение типа A
брошено, для которых нет ни одного обработчика. В блоке finally
выбрано исключение типа B
, для которого имеется обработчик. Обычно исключения, заброшенные в finally
, блокируют победу, но для необработанных исключений это отличается.
При отладке отладчик прекращает выполнение при вызове A
и не разрешает выполнение блока finally
.
Когда не выполняется отладка (выполняется автономно из командной строки), отображается сообщение (распечатанное и диалоговое окно сбоя) об необработанном исключении, но после этого «Все сделано!» распечатывается.
При добавлении обработчика исключений верхнего уровня, который делает не что иное, как реконструировать пойманное исключение, все в порядке: нет неожиданных сообщений и «Все сделано!». печатается.
Я понимаю, как это происходит: определение того, произошло ли исключение обработчиком до того, как будут выполнены кадры finally
. Это обычно желательно, и текущее поведение имеет смысл. finally
блоки вообще не должны исключать исключения.
Но this other Stack Overflow question ссылается на спецификацию языка C# и утверждает, что блок finally
требуется для переопределения исключения A
. Читая спецификацию, я согласен, что это именно то, что он требует:
- В текущем элементе функции, каждая из которых
try
заявление, охватывающую рассматривается точка броска. Для каждого оператораS
, начиная с внутренним оператором Ьги и заканчивая внешний оператором Ьги следующих шаги оцениваются:
- Если
try
блокаS
охватывает точку броска и, если S имеет один или несколькоcatch
положения, Защелка статья рассматривается [...]- в противном случае, если
try
блока илиcatch
блокаS
охватывает точку броска и еслиS
имеетfinally
блок, управление передается наfinally
блока. Если блокfinally
вызывает другое исключение, обработка текущего исключения прекращается. В противном случае, когда управление достигает конечной точки блокаfinally
, обработка текущего исключения продолжается.- Если обработчик исключений не находится в текущем вызове функции, то вызов функции завершается, и одно из следующих событий:
- [...]
- Если обработка исключений завершает все вызовы членов функции в текущем потоке, указывая на то, что поток не имеет обработчика для исключения, тогда сам поток завершается. Влияние такого прекращения определяется реализацией.
Исключение не считается необработанной, в соответствии с моим чтением спецификации, до после все вызовы функции не были прекращены, и вызовы функции не прекращается до тех пор, finally
обработчики не выполняются.
Я что-то упустил, или реализация Microsoft на C# не соответствует их собственной спецификации?
Комментарии для расширенного обсуждения; этот разговор был [перемещен в чат] (http://chat.stackoverflow.com/rooms/65219/discussion-on-question-by-hvd-changing-an-unhandled-exception-to-a-handled-one- я). –
Формулировка немного неуклюжие, возможно, намеренно. Но спецификация CLR не оставляет никаких сомнений в этом, глава I.12.4.2.5 делает его кристально чистым, что, наконец, блоки только выполняются * после того, как он выполнил поиск и нашел обработчик. –