시도 블록에서 값을 반환하면 마지막으로 명세서에서 코드가 발사됩니까?

StackOverflow https://stackoverflow.com/questions/345091

문제

나는 친구에 대한 코드를 검토하고 있으며, 그가 시험을 시도하는 블록 내부에 반환 문을 사용하고 있다고 말합니다. 나머지 시도 블록이 그렇지 않더라도 마지막 섹션의 코드가 여전히 발사됩니까?

예시:

public bool someMethod()
{
  try
  {
    return true;
    throw new Exception("test"); // doesn't seem to get executed
  }
  finally
  {
    //code in question
  }
}
도움이 되었습니까?

해결책

간단한 답변 : 예.

다른 팁

일반적으로 그렇습니다. 마지막 섹션은 예외 또는 반환 명령문을 포함하여 발생하는 모든 일을 실행하도록 보장됩니다. 이 규칙의 예외는 스레드에서 발생하는 비동기 예외입니다 (OutOfMemoryException, StackOverflowException).

해당 상황에서 비동기 예외 및 신뢰할 수있는 코드에 대해 자세히 알아 보려면 제한된 실행 영역.

약간의 테스트가 있습니다.

class Class1
{
    [STAThread]
    static void Main(string[] args)
    {
        Console.WriteLine("before");
        Console.WriteLine(test());
        Console.WriteLine("after");
    }

    static string test()
    {
        try
        {
            return "return";
        }
        finally
        {
            Console.WriteLine("finally");
        }
    }
}

결과는 다음과 같습니다.

before
finally
return
after

MSDN에서 인용

마지막으로 이전의 방법에 관계없이 코드의 명세서 블록을 보장하는 데 사용됩니다. 노력하다 블록입니다 종료.

일반적으로 그렇습니다. 마침내 실행됩니다.

다음 세 가지 시나리오의 경우 마침내 의지가 있습니다 언제나 운영:

  1. 예외가 발생하지 않습니다
  2. 동기 예외 (정상 프로그램 흐름에서 발생하는 예외).
    여기에는 System.Exception에서 파생 된 CLS 준수 예외가 포함되며 System.Exception에서 파생되지 않는 비 CLS 호환 예외가 포함됩니다. 비 CLS 준수 예외는 RuntimeWrappedException에 의해 자동으로 포장됩니다. C#은 비 CLS 불만 예외를 제외 할 수 없지만 C ++와 같은 언어는 캔을 제외 할 수 없습니다. C#은 CLS를 준수하지 않는 예외를 던질 수있는 언어로 작성된 코드로 호출 할 수 있습니다.
  3. 비동기식 나사 보류 렉스
    .NET 2.0 기준으로 ThreadabortException은 더 이상 마침내 실행되는 것을 막지 않습니다. ThreadabortException은 이제 마침내 전후에 들어 섰습니다. 마침내 스레드 중단이 발생하기 전에 실제로 시도되는 한 실이 항상 실행되며 스레드 중단으로 인해 방해되지 않습니다.

다음 시나리오는 마침내 실행되지 않습니다.

비동기식 stackoverflowexception.
.NET 2.0 기준으로 스택 오버 플로우로 인해 프로세스가 종료됩니다. 마지막으로 제약이 적용되지 않으면 마지막으로 실행되지 않습니다. CERS는 일반 사용자 코드에서 사용해서는 안됩니다. 정리 코드가 항상 실행되는 것이 중요한 경우에만 사용해야합니다. 모든 프로세스가 스택 오버 플로우에서 종료 된 후에는 모든 관리되는 객체가 기본적으로 정리됩니다. 따라서, 인식이 관련되어야하는 유일한 장소는 프로세스 외부에 할당되는 리소스 (예 : 관리되지 않는 핸들)입니다.

일반적으로 관리되지 않는 코드는 사용자 코드에 의해 소비되기 전에 일부 관리 클래스에 의해 포장됩니다. 관리되는 래퍼 클래스는 일반적으로 관리되지 않은 손잡이를 감싸기 위해 안전 핸들을 사용합니다. Safehandle은 중요한 최종화기와 CER에서 실행되는 릴리스 방법을 구현하여 정리 코드의 실행을 보장합니다. 이러한 이유로 CERS가 아웃 사용자 코드를 가로 지르는 것을 보지 않아야합니다.

따라서 최종적으로 stackoverflowexception에서 실행되지 않는다는 사실은 프로세스가 종료되기 때문에 사용자 코드에 영향을 미치지 않아야합니다. Safe Handle 또는 CriticalFinalizerObject 외부에서 관리되지 않는 리소스를 정리 해야하는 Edge Case가있는 경우 다음과 같이 CER을 사용하십시오. 그러나 이것은 나쁜 관행입니다. 관리되지 않은 개념은 관리 된 클래스 (ES)와 디자인으로 적절한 안전 핸들로 추상화되어야합니다.

예,

// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{ 
    // This is *NOT* a CER
}
finally
{
    // This is a CER; guaranteed to run, if the try was entered, 
    // even if a StackOverflowException occurs.
}

다른 답변에서 언급하지 않은 이에 대한 매우 중요한 예외가 있으며 (18 년 동안 C#로 프로그래밍 한 후) 나는 몰랐다고 믿을 수 없습니다.

예외를 던지거나 트리거하는 경우 어느 당신의 안에 정렬하십시오 catch 블록 (이상한 것이 아닙니다 StackOverflowExceptions 그리고 그 ilk의 것들), 당신은 전체가 없습니다. try/catch/finally 다른 내부를 차단하십시오 try/catch 블록, 당신 finally 블록은 실행되지 않습니다. 이것은 쉽게 입증 될 수 있습니다. 그리고 내가 직접 보지 못했다면 얼마나 자주 읽은지를 주면 정말 이상하고 작은 코너 케이스가 finally 실행하지 말고, 나는 그것을 믿지 않았을 것입니다.

static void Main(string[] args)
{
    Console.WriteLine("Beginning demo of how finally clause doesn't get executed");
    try
    {
        Console.WriteLine("Inside try but before exception.");
        throw new Exception("Exception #1");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Inside catch for the exception '{ex.Message}' (before throwing another exception).");
        throw;
    }
    finally
    {
        Console.WriteLine("This never gets executed, and that seems very, very wrong.");
    }

    Console.WriteLine("This never gets executed, but I wasn't expecting it to."); 
    Console.ReadLine();
}

나는 이것에 대한 이유가 있다고 확신하지만, 더 널리 알려지지 않은 것은 기괴합니다. (주목됩니다 여기 예를 들어,이 특정 질문의 어느 곳에서나는 아닙니다.)

나는 파티에 늦었다는 것을 알고 있지만 시나리오에서 (OP의 예와는 다름) 실제로 예외가 MSDN 상태로 던져진다는 것을 알고 있습니다.https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx): "예외가 잡히지 않으면 최종 블록의 실행은 운영 체제가 예외 UNFIND 운영을 트리거하기로 선택하는지 여부. "

마침내 블록은 전용입니다 보장 다른 함수 (예 : 메인)가 콜 스택이 예외를 포착하는 경우 실행하려면 예외가 발생합니다. 모든 실행 시간 환경 (CLR 및 OS) C# 프로그램은 종료 할 때 프로세스가 소유하는 대부분의 리소스 (파일 핸들 등)에서 실행되기 때문에이 세부 사항은 일반적으로 문제가되지 않습니다. 어떤 경우에는 중요 할 수도 있습니다. 데이터베이스 작업 중 절반이 진행되고 싶습니다. 풀다; 또는 OS에 의해 자동으로 닫히지 않을 수있는 일부 원격 연결이 서버를 차단합니다.

예. 그것은 사실 마침내 진술의 주요 요점입니다. Catestrophic이 발생하지 않는 한 (메모리에서, 컴퓨터를 뽑지 않은 등) 마지막으로 진술은 항상 실행되어야합니다.

또한 끊임없는 예외로는 발사되지 않고 Windows 서비스에서 호스팅 된 스레드에서 실행됩니다.

마지막으로 Windows 서비스에서 실행되는 스레드에서 실행되지 않습니다.

System.Exit (0)를 사용하여 응용 프로그램에서 나오는 경우에도 실행되지 않습니다. 에서와 같이

try
{
    System.out.println("try");
    System.exit(0);
}
finally
{
   System.out.println("finally");
}

결과는 단지 다음과 같습니다. 시도하십시오

시나리오의 99%는 내부의 코드가 finally 그러나 블록은이 시나리오를 생각할 것입니다. try->finally 블록 (아니요 catch) 그리고 당신은 그 스레드 내에서 처리되지 않은 예외를 얻습니다. 이 경우 스레드가 종료되고 그 finally 블록은 실행되지 않습니다 (이 경우 응용 프로그램은 계속 실행할 수 있습니다)

이 시나리오는 매우 드물지만 대답이 항상 "예"가 아니라는 것을 보여주는 것만으로도 대부분 "예"이며 때로는 드문 조건에서 "아니오"입니다.

마지막으로 블록의 주요 목적은 그 안에 쓰여진 모든 것을 실행하는 것입니다. System.environment.exit (1)로 시도하거나 Catch.ect에서 발생하는 일에 의존해서는 안됩니다.

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