catch 블록에서 예외를 던지면 마지막으로 언제 실행됩니까?


135
try {
   // Do stuff
}
catch (Exception e) {
   throw;
}
finally {
   // Clean up
}

위의 블록에서 finally 블록은 언제 호출됩니까? e를 던지기 전에 또는 마지막으로 부름을 받아 붙잡는가?


14
ps 당신은 "e를 던지지 말아야한다"; 원래 예외의 스택 추적을 망칠 수 있기 때문입니다. 당신은 단지 "던져야한다". 또는 새 예외를 만들고 던지기 전에 InnerException을 "e"로 설정하십시오.
Erv Walter

24
마지막 으로 키워드가 마지막으로 실행되지 않은 경우 마지막 으로 키워드를 잘못 선택했을 것입니다 .
Eric Lippert

@ ErvWalter 이것은 여전히 ​​사실입니까? VS2017에서 두 가지 방법으로 테스트 중이며 정확히 동일한 것으로 보입니다. 더 자세한 정보 나 참조를 제공해 주시겠습니까? 감사합니다
Jeff Puckett

그냥 명명 제안 사용 예외 / 사전 예약 e
미스터 R

답변:


138

e가 다시 던져진 후 (즉, catch 블록이 실행 된 후) 호출됩니다.

이 7 년 후 편집 – 한 가지 중요한 점은 etry / catch 블록에 의해 호출 스택을 더 이상 잡지 않거나 전역 예외 처리기에 의해 처리 되지 않으면 finally블록 전혀 실행될 없다는 것입니다.


18
Envrionment.FailFast ()
Johannes Rudolph 님이

16
브랜든의 대답에 코드를 시도 후, 나는이 것을 볼 finally이전에 던져 예외가있는 경우 실행되지 catch않습니다 잡은없는 외부에서 try- catch블록!
앤드류

3
새 정보를 포함하도록 (허용되는) 답변을 편집 해 주셔서 감사합니다.
Gordon Bean

3
그들 (Microsoft)은 새 문서 사이트 docs.microsoft.com/en-us/dotnet/csharp/language-reference/… 에서 이에 대해 이야기합니다 . "처리 된 예외 내에서 연관된 finally 블록이 실행되도록 보장됩니다. 예외가 처리되지 않으면 finally 블록의 실행은 예외 해제 작업이 어떻게 트리거되는지에 따라 달라집니다. 결과적으로 컴퓨터 설정 방법에 따라 달라집니다. "
DotNetSparky 2016 년

1
"try / catch 블록에 의해 호출 스택을 더 많이 잡아 냄"에는 ASP.NET 또는 테스트 러너와 같은 프레임 워크 핸들러가 포함됩니다. "캐치 블록 후에 프로그램이 계속 실행되면 finally 블록이 실행됩니다."
ArrowCase

91

시도해 보지 않겠습니까?

outer try
inner try
inner catch
inner finally
outer catch
outer finally

코드 포함 (수직 공간 용) :

static void Main() {
    try {
        Console.WriteLine("outer try");
        DoIt();
    } catch {
        Console.WriteLine("outer catch");
        // swallow
    } finally {
        Console.WriteLine("outer finally");
    }
}
static void DoIt() {
    try {
        Console.WriteLine("inner try");
        int i = 0;
        Console.WriteLine(12 / i); // oops
    } catch (Exception e) {
        Console.WriteLine("inner catch");
        throw e; // or "throw", or "throw anything"
    } finally {
        Console.WriteLine("inner finally");
    }
}

5
+1, 아주 간단한 무언가를 위해, 당신은 Marc처럼 실제로 시도해야합니다. GJ는 try / catch / finally로 중첩 된 것을 보여줍니다 :)
Allen Rice

1
@AllenRice Marc가 이미 가지고 있다면 왜 그것을 시도하고 Marc의 답변을 찾기 위해 Google을 사용할 수 있습니까? 또는 더 나은 방법으로 자신을 시험 한 다음 SO 질문을 작성하고 다른 사람의 이익을 위해 스스로 대답하십시오.
joshden

8
외부 캐치에서 예외를 포착하지 않으면 내부가 최종적으로 실행되지 않습니다! 이 경우 출력은outer try inner try inner catch Unhandled Exception: System.DivideByZeroException...
Andrew

1
@Andrew 당신이 맞아요. 당신은 여기에서 찾을 수 있습니다 설명 MSDN 매거진 2008 년 9 월 : CLR에 처리되지 않은 예외 처리 (오픈 CHM에 그것을 해제 할 필요가 : 파일 속성 -> 일반 -> 잠금 해제). 외부 캐치 블록을 "catch (ArgumentException)"으로 바꾸면 CLR에서 "예외를 처리하기로 동의 한 예외 처리기"DivideByZeroException을 찾을 수 없기 때문에 아무도 마지막으로 블록을 진행하지 않습니다.
vladimir

35

최종 대답은 같이 여기에 대한 답변을 모두 읽은 후에는 보이는 것이 달려있다 :

  • catch 블록 내에서 예외를 다시 발생시키고 해당 예외가 다른 catch 블록 내에서 포착되면 모든 것이 문서에 따라 실행됩니다.

  • 그러나 다시 자르기 예외가 처리되지 않으면 최종 실행은 절대 실행되지 않습니다.

이 코드 샘플을 VS2010 w / C # 4.0에서 테스트했습니다.

static void Main()
    {
        Console.WriteLine("Example 1: re-throw inside of another try block:");

        try
        {
            Console.WriteLine("--outer try");
            try
            {
                Console.WriteLine("----inner try");
                throw new Exception();
            }
            catch
            {
                Console.WriteLine("----inner catch");
                throw;
            }
            finally
            {
                Console.WriteLine("----inner finally");
            }
        }
        catch
        {
            Console.WriteLine("--outer catch");
            // swallow
        }
        finally
        {
            Console.WriteLine("--outer finally");
        }
        Console.WriteLine("Huzzah!");

        Console.WriteLine();
        Console.WriteLine("Example 2: re-throw outside of another try block:");
        try
        {
            Console.WriteLine("--try");
            throw new Exception();
        }
        catch
        {
            Console.WriteLine("--catch");
            throw;
        }
        finally
        {
            Console.WriteLine("--finally");
        }

        Console.ReadLine();
    }

출력은 다음과 같습니다.

예 1 : 다른 try 블록 내부에서 다시 던지기 :
--outer try
---- inner try
---- inner catch
---- inner finally
--outer catch
--outer finally
Huzzah!

예 2 : 다른 try 블록 외부에서 다시 던지기 :
--try
--catch

처리되지 않은 예외 : System.Exception : 'System.Exception'유형의 예외가 발생했습니다.
C : \ local source \ ConsoleApplication1 \ Program.cs : line의 ConsoleApplication1.Program.Main ()에서 53


3
큰 캐치, 나는 그것을 몰랐다!
앤드류

1
참고 마지막은 마지막으로 선택한 내용에 따라 실행할 수 : stackoverflow.com/a/46267841/480982
토마스 웰러에게

1
흥미로운 ... .NET Core 2.0에서 마지막 부분은 처리되지 않은 예외 후에 실행됩니다.
Mahdi Ghiasi

흥미롭게도 .NET Core 2.0과 .NET Framework 4.6.1 모두에서 테스트를 수행했으며 처리되지 않은 예외 후에 마침내 실행됩니다. 이 동작이 변경 되었습니까?
카메론 비엘 슈타인

24

귀하의 예는 다음 코드와 동일하게 작동합니다.

try {
    try {
        // Do stuff
    } catch(Exception e) {
        throw e;
    }
} finally {
    // Clean up
}

부수적으로, 실제로 의미하는 경우 throw e;(즉, 방금 잡은 것과 동일한 예외를 던짐) 새 스택을 만드는 대신 원래 스택 추적을 유지하기 때문에 수행 하는 것이 훨씬 좋습니다 throw;.


나는 이것이 옳지 않다고 생각합니다. 마지막으로 외부 외부 블록 외부에 있어야합니다.
Matthew Pigram

@MatthewPigram : 무슨 뜻인가요? finally블록은 실제로 후에 실행됩니다 catch내 조각이 설명하려고하는 것입니다 블록 (catch 블록은 예외를 rethrows 경우에도).
Daniel Pryden

내가 그의 예를 어떻게 해석하는지에 따라 그는 다른 try 블록 내에서 마침내 try catch를 시도합니다. 마지막으로 시도 캐치 내 NOT 시도 캐치
마태 복음 Pigram

1
@MatthewPigram : 내 대답에는 "try-catch-finally"구문이 전혀 없습니다. 그것은 "마침내 시도"를 가지고 있으며 그 try블록 안에는 "시도 잡기"가 있습니다. 두 부분으로 구성된 두 가지 구문을 사용하여 3 부분으로 구성된 구문의 동작을 설명하려고합니다. try원래 질문에 두 번째 블록의 흔적 이 보이지 않으므로 어디에서 얻을 수 있는지 이해할 수 없습니다.
Daniel Pryden

12

catch 처리기 블록 내에 처리되지 않은 예외가 있으면 finally 블록이 정확히 0 번 호출됩니다.

  static void Main(string[] args)
  {
     try
     {
        Console.WriteLine("in the try");
        int d = 0;
        int k = 0 / d;
     }
     catch (Exception e)
     {
        Console.WriteLine("in the catch");
        throw;
     }
     finally
     {
        Console.WriteLine("In the finally");
     }
  }

산출:

C : \ users \ administrator \ documents \ TestExceptionNesting \ bin \ Release> TestExceptionNesting.exe

시도에서

캐치

처리되지 않은 예외 : System.DivideByZeroException : 0으로 나누려고했습니다. C : \ users \ administrator \ documents \ TestExceptionNesting \ TestExceptionNesting.cs : line의 TestExceptionNesting.Program.Main (String [] args)에서 22 행

C : \ users \ administrator \ documents \ TestExceptionNesting \ bin \ release>

나는 오늘 인터뷰에서이 질문을 받았고 인터뷰자는 계속해서 "마지막으로 불려지지 않습니까?" 그것이 트릭 질문인지 아니면 면접관이 다른 것을 염두에두고 디버깅하기 위해 잘못된 코드를 작성했는지 확실하지 않았으므로 집에 와서 시도해 보았습니다 (디버거 상호 작용 없음). 쉬다.


던져진 예외가 스택의 상위에있는 다른 캐치에 걸리지 않는 한, 예외가 처리되면 실행될 수 있습니다 ... 또는 잘못되었을 수 있습니다 ...
tomosius

@tomosius, 그렇습니다. Brandon의 대답이 설명합니다. :)
Andrew

@tomosius 그렇기 때문에 "처리되지 않은 예외가있는 경우"를 지정하여 시작했습니다. 던져진 예외가 어딘가에 잡히면 정의에 따라 다른 경우에 대해 이야기하고 있습니다.
Eusebio Rufian-Zilbermann

사실이 아닙니다. NET Core 3.1 이상은 아닙니다. 이 코드가 포함 된 간단한 새 콘솔 프로젝트는 예외 후에 "in the finally"를 표시합니다.
emzero

동작이 변경되었다는 사실에 흥미를
느낀

2

간단한 방법은 코드를 디버깅하고 마지막으로 호출 될 때 알림을받는 것입니다.


1

C # 콘솔 응용 프로그램을 사용한 테스트에서 예외가 발생한 후 최종 코드가 실행되었습니다. "응용 프로그램 오류 대화 상자"가 존재하고 "프로그램 닫기"옵션을 선택한 후 finally 블록이 해당 콘솔 창에서 실행되었습니다. 그러나 finally 코드 블록 안에 중단 점을 설정하면 절대로 칠 수 없습니다. 디버거는 throw 문에서 계속 중지합니다. 내 테스트 코드는 다음과 같습니다.

    class Program
    {
       static void Main(string[] args)
       {
          string msg;
          Console.WriteLine(string.Format("GetRandomNuber returned: {0}{1}", GetRandomNumber(out msg), msg) == "" ? "" : "An error has occurred: " + msg);
       }

       static int GetRandomNumber(out string errorMessage)
       {
         int result = 0;
         try
         {
            errorMessage = "";
            int test = 0;
            result = 3/test;
            return result;
         }
         catch (Exception ex)
         {
            errorMessage = ex.Message;
            throw ex;

         }
         finally
         {
            Console.WriteLine("finally block!");
         }

       }
    }

VS2010에서 디버깅-.NET Framework 4.0

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.