Что произойдет, если блок finally выдает исключение?

Если блок finally генерирует исключение, что именно происходит?

В частности, что произойдет, если исключение будет выброшено на полпути через блок finally. Вызывают ли остальные инструкции (после) в этом блоке?

Я знаю, что исключения будут распространяться вверх.

    Если блок finally генерирует исключение, что именно происходит?

    Это исключение распространяется и расширяется и будет (может) обрабатываться на более высоком уровне.

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

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

    Спецификация языка C # 4 § 8.9.5: Если блок finally генерирует другое исключение, обработка текущего исключения прекращается.

    Для таких вопросов я обычно открываю пустой проект консольного приложения в Visual Studio и пишу небольшую примерную программу:

     using System; class Program { static void Main(string[] args) { try { try { throw new Exception("exception thrown from try block"); } catch (Exception ex) { Console.WriteLine("Inner catch block handling {0}.", ex.Message); throw; } finally { Console.WriteLine("Inner finally block"); throw new Exception("exception thrown from finally block"); Console.WriteLine("This line is never reached"); } } catch (Exception ex) { Console.WriteLine("Outer catch block handling {0}.", ex.Message); } finally { Console.WriteLine("Outer finally block"); } } } 

    Когда вы запустите программу, вы увидите точный порядок, в котором выполняются блоки catch и finally . Обратите внимание, что код в блоке finally после генерируемого исключения не будет выполнен (на самом деле, в этом примере программа Visual Studio даже предупредит вас, что обнаружила недостижимый код):

     Исключение исключений блокировки внутреннего блока, отбрасываемых из блока try.
     Внутренний окончательный блок
     Исключение обработчика внешнего блока catch, отбрасываемого из блока finally.
     Наружный блок finally
    

    Дополнительное примечание

    Как отметил Майкл Даматов, исключение из блока try будет «съедено», если вы не будете обрабатывать его во внутреннем блоке catch . Фактически, в приведенном выше примере повторное исключение исключений не появляется во внешнем блоке catch. Чтобы сделать это еще более ясным, рассмотрим следующий слегка измененный пример:

     using System; class Program { static void Main(string[] args) { try { try { throw new Exception("exception thrown from try block"); } finally { Console.WriteLine("Inner finally block"); throw new Exception("exception thrown from finally block"); Console.WriteLine("This line is never reached"); } } catch (Exception ex) { Console.WriteLine("Outer catch block handling {0}.", ex.Message); } finally { Console.WriteLine("Outer finally block"); } } } 

    Как видно из вывода, внутреннее исключение «потеряно» (т.е. игнорируется):

     Внутренний окончательный блок
     Исключение обработчика внешнего блока catch, отбрасываемого из блока finally.
     Наружный блок finally
    

    Если ожидаемое исключение (когда блок try имеет окончание, но не catch ), новое исключение заменяет это.

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

    Исключение распространяется.

    Быстрый (и довольно очевидный) fragment, чтобы сохранить «исходное исключение» (брошенное в блок try ) и жертвовать «окончательным исключением» (брошенным в блок finally ), в случае, если для вас важнее оригинал:

     try { throw new Exception("Original Exception"); } finally { try { throw new Exception("Finally Exception"); } catch { } } 

    Когда выполняется код выше, «Исходное исключение» распространяет стек вызовов, и «Exception Exception» теряется.

    Я должен был сделать это, чтобы поймать ошибку, пытаясь закрыть stream, который никогда не был открыт из-за исключения.

     errorMessage = string.Empty; try { byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(xmlFileContent); webRequest = WebRequest.Create(url); webRequest.Method = "POST"; webRequest.ContentType = "text/xml;charset=utf-8"; webRequest.ContentLength = requestBytes.Length; //send the request using (var sw = webRequest.GetRequestStream()) { sw.Write(requestBytes, 0, requestBytes.Length); } //get the response webResponse = webRequest.GetResponse(); using (var sr = new StreamReader(webResponse.GetResponseStream())) { returnVal = sr.ReadToEnd(); sr.Close(); } } catch (Exception ex) { errorMessage = ex.ToString(); } finally { try { if (webRequest.GetRequestStream() != null) webRequest.GetRequestStream().Close(); if (webResponse.GetResponseStream() != null) webResponse.GetResponseStream().Close(); } catch (Exception exw) { errorMessage = exw.ToString(); } } 

    если webRequest был создан, но ошибка соединения произошла во время

     using (var sw = webRequest.GetRequestStream()) 

    то, наконец, будет обнаружено исключение, пытающееся закрыть соединения, которые, по его мнению, были открыты, потому что было создано webRequest.

    Если у finally не было try-catch внутри, этот код вызовет необработанное исключение, очистив webRequest

     if (webRequest.GetRequestStream() != null) 

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

    Надеюсь, это поможет в качестве примера

    Выброс исключения, когда активен другой исключение, приведет к тому, что первое исключение будет заменено вторым (последующим) исключением.

    Вот какой код, который иллюстрирует, что происходит:

      public static void Main(string[] args) { try { try { throw new Exception("first exception"); } finally { //try { throw new Exception("second exception"); } //catch (Exception) { //throw; } } } catch (Exception e) { Console.WriteLine(e); } } 
    • Запустите код, и вы увидите «второе исключение»
    • Разобейте заявления try и catch, и вы увидите «первое исключение»,
    • Также раскомментируйте бросок; и вы снова увидите «второе исключение».

    Несколько месяцев назад я тоже столкнулся с чем-то вроде этого,

      private void RaiseException(String errorMessage) { throw new Exception(errorMessage); } private void DoTaskForFinally() { RaiseException("Error for finally"); } private void DoTaskForCatch() { RaiseException("Error for catch"); } private void DoTaskForTry() { RaiseException("Error for try"); } try { /*lacks the exception*/ DoTaskForTry(); } catch (Exception exception) { /*lacks the exception*/ DoTaskForCatch(); } finally { /*the result exception*/ DoTaskForFinally(); } 

    Чтобы решить такую ​​проблему, я сделал class полезности, например

     class ProcessHandler : Exception { private enum ProcessType { Try, Catch, Finally, } private Boolean _hasException; private Boolean _hasTryException; private Boolean _hasCatchException; private Boolean _hasFinnallyException; public Boolean HasException { get { return _hasException; } } public Boolean HasTryException { get { return _hasTryException; } } public Boolean HasCatchException { get { return _hasCatchException; } } public Boolean HasFinnallyException { get { return _hasFinnallyException; } } public Dictionary Exceptions { get; private set; } public readonly Action TryAction; public readonly Action CatchAction; public readonly Action FinallyAction; public ProcessHandler(Action tryAction = null, Action catchAction = null, Action finallyAction = null) { TryAction = tryAction; CatchAction = catchAction; FinallyAction = finallyAction; _hasException = false; _hasTryException = false; _hasCatchException = false; _hasFinnallyException = false; Exceptions = new Dictionary(); } private void Invoke(Action action, ref Boolean isError, ProcessType processType) { try { action.Invoke(); } catch (Exception exception) { _hasException = true; isError = true; Exceptions.Add(processType.ToString(), exception); } } private void InvokeTryAction() { if (TryAction == null) { return; } Invoke(TryAction, ref _hasTryException, ProcessType.Try); } private void InvokeCatchAction() { if (CatchAction == null) { return; } Invoke(TryAction, ref _hasCatchException, ProcessType.Catch); } private void InvokeFinallyAction() { if (FinallyAction == null) { return; } Invoke(TryAction, ref _hasFinnallyException, ProcessType.Finally); } public void InvokeActions() { InvokeTryAction(); if (HasTryException) { InvokeCatchAction(); } InvokeFinallyAction(); if (HasException) { throw this; } } } 

    И используется так

     try { ProcessHandler handler = new ProcessHandler(DoTaskForTry, DoTaskForCatch, DoTaskForFinally); handler.InvokeActions(); } catch (Exception exception) { var processError = exception as ProcessHandler; /*this exception contains all exceptions*/ throw new Exception("Error to Process Actions", exception); } 

    но если вы хотите использовать параметры и возвращаемые типы, это другая история

     public void MyMethod() { try { } catch{} finally { CodeA } CodeB } 

    То, как обрабатываются исключения, переданные CodeA и CodeB, одинаково.

    Исключение, созданное в блоке finally , не имеет ничего особенного, рассматривайте его как бросок исключения кодом B.

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

    Независимо от того, существует ли исключение или нет, блок «finally» гарантированно исполняется.

    1. Если блок «finally» выполняется после того, как в блоке try произошло исключение,

    2. и если это исключение не обрабатывается

    3. и если блок finally выдает исключение

    Тогда исходное исключение, которое произошло в блоке try, теряется.

     public class Exception { public static void Main() { try { SomeMethod(); } catch (Exception ex) { Console.WriteLine(ex.Message); } } public static void SomeMethod() { try { // This exception will be lost throw new Exception("Exception in try block"); } finally { throw new Exception("Exception in finally block"); } } } 

    Отличная статья для деталей

    Он выдает исключение;) Вы можете поймать это исключение в другом предложении catch.

    Давайте будем гением компьютера.