문제

이 코드를 가져 가십시오 :

using System;

namespace OddThrow
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                throw new Exception("Exception!");
            }
            finally
            {
                System.Threading.Thread.Sleep(2500);
                Console.Error.WriteLine("I'm dying!");
                System.Threading.Thread.Sleep(2500);
            }
        }
    }
}

이 출력을 제공합니다.

Unhandled Exception: System.Exception: Exception!
   at OddThrow.Program.Main(String[] args) in C:\Documents and Settings\username
\My Documents\Visual Studio 2008\Projects\OddThrow\OddThrow\Program.cs:line 14
I'm dying!

내 질문은 다음과 같습니다. 도대치되지 않은 예외 텍스트가 왜 마침내 시작되기 전에 발생합니까? 내 마음 속에는 마침내 스택이 풀리면서 마침내 탁월해야합니다. 알다 이 예외는 도달되지 않습니다. 수면에 대한 통화에 유의하십시오 () - 이런 일이 발생합니다. ~ 후에 처리되지 않은 예외는 다음과 같이 인쇄됩니다.

  1. 처리되지 않은 예외 텍스트/메시지
  2. 마침내 블록.
  3. 신청 종료

C# Standard, §8.9.5에 따르면이 동작은 잘못되었습니다.

  • 현재 함수 멤버에서, 던지는 지점을 동봉하는 각 try 문을 검사합니다. 각 진술에 대해, 가장 안쪽 시도 문으로 시작하여 가장 바깥 쪽 시도 문으로 끝나는 다음 단계가 평가됩니다.
    • S의 시도 블록이 던지기 포인트를 둘러싸고 S에 하나 이상의 캐치 조항이있는 경우, 예외에 적합한 핸들러를 찾기 위해 외관 순서로 캐치 조항을 검사합니다. 예외 유형 또는 예외 유형의 기본 유형을 지정하는 첫 번째 캐치 절은 일치하는 것으로 간주됩니다. 일반 캐치 절 (§8.10)은 모든 예외 유형과 일치하는 것으로 간주됩니다. 일치하는 캐치 조항이있는 경우 해당 캐치 절의 블록으로 제어를 전송하여 예외 전파가 완료됩니다.
    • 그렇지 않으면, S의 시도 블록 또는 S 캐치 블록이 던지기 점을 동봉하고 S에 최종적으로 블록이있는 경우, 제어는 최종 블록으로 전송된다. 마지막으로 블록이 다른 예외를 던지면 현재 예외의 처리가 종료됩니다. 그렇지 않으면, 제어가 최종 블록의 종말점에 도달하면, 현재 예외의 처리가 계속된다.
  • 현재 함수 멤버 호출에 예외 핸들러가 없으면 함수 멤버 호출이 종료됩니다. 그런 다음 위의 단계는 함수 멤버의 발신자에 대해 함수 멤버가 호출 된 명령문에 해당하는 던지기 점을 가진 함수 멤버의 발신자에 대해 반복됩니다.
  • 예외 처리가 현재 스레드에서 모든 함수 멤버 호출을 종료하면 스레드에 예외가 없음을 나타내면 스레드 자체가 종료됩니다. 이러한 종료의 영향은 구현 정의됩니다.

내가 어디로 잘못 가고 있습니까? (나는 몇 가지 사용자 정의 콘솔 오류 메시지가 있고 이것은 내면의입니다. 미성년자, 단지 성가시고 언어에 의문을 제기합니다 ...)

도움이 되었습니까?

해결책

실행 순서에 대한 표준의 진술은 정확하며 관찰하는 것과 일치하지 않습니다. "처리되지 않은 예외"메시지는 어느 CLR의 메시지 일뿐 아니라 실제로 예외 핸들러 자체가 아니기 때문에 프로세스를 가리키십시오. 실행 순서에 대한 규칙은 CLR 자체가 아닌 CLR 내부에서 실행되는 코드에만 적용됩니다.

실제로 수행 한 것은 구현 세부 사항을 노출시키는 것입니다.이 구현 세부 사항은 실제로 루트까지 모든 길을 탐색하는 것이 아니라 내부에있는 {} 블록을 시도하는 스택을 보면 인식됩니다. 예외는 그렇지 않을 수 있습니다 처리 이 스택을 살펴보면 이런 방식으로 처리되지 않은 예외가 인식됩니다.

아시다시피, 메인 함수에 최상위 레벨을 시도하면 {} catch {}을 입력하면 예상되는 동작이 표시됩니다. 매칭 캐치 {다음 프레임을 확인하기 전에 각 기능이 실행됩니다. }.

다른 팁

나는 내가 물건을 읽는 방식에 따라 기지에서 벗어날 수 있습니다 ... 그러나 당신은 마침내 캐치없이 차단해야합니다.

당신이 게시 한 설명에 의해, 예외는 결코 잡히지 않기 때문에, 발신자에게 거품이 생기고, 스택을 통과하는 길을 작동시키고, 결국 도둑이 끊어지고, 전화가 끝나고, 마지막으로 블록이 호출됩니다.

출력은 실제로 기본 CLR 예외 처리기에서 나온 것입니다. 예외 처리기는 마지막으로 블록 전에 발생합니다. 마지막으로 블록 후 CLR은 처리되지 않은 예외로 인해 종료됩니다 (C#이 마지막 절이 호출되는 것을 보장하기 때문에 이전에 종료 할 수 없습니다).

그래서 나는 그것이 단지 표준 행동이라고 말하고, 예외 처리는 마지막으로 전에 발생합니다.

1] 적어도 내부 런타임 오류 또는 정전이없는 경우 정상 작동 중 guranteed

이 기사가 여기서 무슨 일이 일어나고 있는지 더 자세히 이해하는 데 도움이 될 수 있다고 생각합니다.

http://bartdesmet.net/blogs/bart/archive/2006/04/04/clr-exception-handling-from-o-zeverything-you--didn-t-want-to- know-about- Try-Catch-Finally-Fault-Filter.aspx

믹스에 더 많은 것을 추가하려면 다음을 고려하십시오.

using System;
namespace OddThrow
{
    class Program
    {
        static void Main()
        {
            AppDomain.CurrentDomain.UnhandledException +=
                delegate(object sender, UnhandledExceptionEventArgs e)
            {
                Console.Out.WriteLine("In AppDomain.UnhandledException");
            };
            try
            {
                throw new Exception("Exception!");
            }
            catch
            {
                Console.Error.WriteLine("In catch");
                throw;
            }
            finally
            {
                Console.Error.WriteLine("In finally");
            }
        }
    }
}

내 시스템 (노르웨이어)에서 다음을 보여줍니다.

[C:\..] ConsoleApplication5.exe
In catch
In AppDomain.UnhandledException

Ubehandlet unntak: System.Exception: Exception!
   ved OddThrow.Program.Main() i ..\Program.cs:linje 24
In finally

완전히 예상되지는 않았지만 프로그램은 예상대로 행동합니다. 마지막으로 블록이 먼저 실행될 것으로 예상되지 않으며 항상 실행될 것으로 예상됩니다.

샘플을 조정했습니다.

public static void Main()
{
    try
    {
        Console.WriteLine("Before throwing");
        throw new Exception("Exception!");
    }
    finally
    {
        Console.WriteLine("In finally");
        Console.ReadLine();
    }
}

이 경우에는 불쾌한 예외 대화 상자를 얻을 수 있지만 나중에 콘솔이 출력하여 입력을 기다립니다. 따라서 Windows 자체가 처리되지 않은 예외를 포착하기 전에 마지막으로 실행됩니다.

캐치가없는 시도/마침내는 기본 핸들러를 사용하여 정확히 보는 작업을 수행합니다. 예외를 처리하는 것이 오류를 다루는 경우에도 항상 사용하지만 여전히 정리하고 싶은 정리가 있습니다.

또한 표준 오류 및 표준 출력에 대한 출력은 버퍼링되어 있음을 기억하십시오.

Try-Catch-Finally 블록은 예상대로 정확하게 작동합니다 그들이 어느 시점에서 잡히면. 이 테스트 프로그램을 작성하고 다양한 중첩 레벨을 사용했을 때, 설명한 방식으로 동작 한 유일한 사례는 코드에 의해 예외가 완전히 처리되지 않고 운영 체제로 거품이 발생했을 때였습니다.

내가 실행할 때마다 OS는 오류 메시지를 생성 한 것입니다. 따라서 문제는 C#에 관한 것이 아니며 사용자 코드에 의해 처리되지 않은 오류는 다음과 같습니다. 더 이상 응용 프로그램을 제어하지 않습니다 그러므로 런타임 (나는 믿는다)은 실행 패턴을 강요 할 수 없다.

Windows 양식 응용 프로그램을 만들고 모든 메시지를 텍스트 상자에 작성한 다음 콘솔에 직접 쓰는 대신 텍스트 상자 (즉시 플러싱)를 작성한 경우 오류 메시지가 오류 콘솔에 삽입 되었기 때문에 해당 오류 메시지가 전혀 보이지 않았을 것입니다. 자신의 코드가 아닌 호출 응용 프로그램에 의해.

편집하다

나는 그것의 핵심 부분을 강조하려고 노력할 것이다. 처리되지 않은 예외는 귀하의 통제를 벗어 났으며 예외 처리기가 언제 실행되는지 확인할 수 없습니다. 예외를 포착하는 경우 어느 시점에서 귀하의 응용 프로그램에서 finally 스택 하단 전에 블록이 실행됩니다 catch 차단하다.

몇 가지 답변을 정리하기 위해, 처리되지 않은 예외가있는 즉시 appDomain에서 처리되지 않은 exceptionEvent가 제기되면 코드가 계속 실행됩니다 (즉, 마침내). 이것이 행사에 관한 MSDN 기사

다음 시도 :

  1. 이 사건은 C# 표준에 언급되지 않았다고 생각하며 거의 모순되는 것 같습니다.

  2. 이런 일이 발생하는 내부 이유는 다음과 같습니다. CLR은 기본 예외 핸들러를 SEH 핸들러로 FS로 등록합니다. [0] 코드에 더 많은 어획량이있을 때 해당 처리기가 SEH 체인에 추가됩니다. 또는 SEH 처리 중에 CLR 핸들러 만 호출되고 내부적으로 CLR 예외 체인을 처리합니다.

코드에서 예외가 발생하면 기본 핸들러 만 SEH 체인에 있습니다. 이 핸들러는 스택 Unrolling이 시작되기 전에 호출됩니다.

기본 예외 핸들러는 스택에 등록 된 예외 핸들러가 없다는 것을 알고 있습니다. 따라서 등록 된 모든 undledlexception 핸들러를 먼저 호출 한 다음 오류 메시지를 인쇄하고 언로드를 위해 AppDomain을 표시합니다.

그 스택이 시작된 후에야 C# 표준에 따라 블록이 호출됩니다.

내가 알 수 있듯이 CLR이 처리되지 않은 예외를 처리하는 방식은 C# 표준에서 고려되지 않으며 스택 Unrolling 중에 마침내 호출되는 순서 만 고려되지 않습니다. 이 명령은 보존됩니다. 그 후 "그러한 종료의 영향은 구현 정의됩니다." 조항이 적용됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top