IT story

Try 블록에 값을 반환하면 Final 문의 코드가 실행됩니까?

hot-time 2020. 4. 19. 13:56
반응형

Try 블록에 값을 반환하면 Final 문의 코드가 실행됩니까?


친구를위한 코드를 검토하고 있으며 try-finally 블록 내부에서 return 문을 사용하고 있다고 말합니다. try 블록의 나머지 부분이 그렇지 않더라도 Final 섹션의 코드가 여전히 실행됩니까?

예:

public bool someMethod()
{
  try
  {
    return true;
    throw new Exception("test"); // doesn't seem to get executed
  }
  finally
  {
    //code in question
  }
}

간단한 대답 : 그렇습니다.


일반적으로 그렇습니다. finally 섹션은 예외 또는 return 문을 포함하여 발생하는 모든 것을 실행하도록 보장됩니다. 이 규칙에 대한 예외는 스레드 ( 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에서 인용

마지막으로 앞의 try 블록이 어떻게 종료 되는지에 관계없이 명령문 코드 블록 실행을 보장하는 데 사용됩니다 .


일반적으로 그렇습니다. 마지막으로 실행됩니다.

다음 세 가지 시나리오의 경우 최종적으로 항상 실행됩니다.

  1. 예외는 발생하지 않습니다
  2. 동기 예외 (정상적인 프로그램 흐름에서 발생하는 예외).
    여기에는 System.Exception에서 파생 된 CLS 호환 예외와 System.Exception에서 파생되지 않은 CLS 비준수 예외가 포함됩니다. CLS 비준수 예외는 RuntimeWrappedException에 의해 자동으로 줄 바꿈됩니다. C #은 CLS 이외의 불만 예외를 처리 할 수 ​​없지만 C ++와 같은 언어는 예외를 처리 할 수 ​​있습니다. C #은 비 CLS 규격 예외를 발생시킬 수있는 언어로 작성된 코드를 호출 할 수 있습니다.
  3. 비동기 ThreadAbortException
    .NET 2.0부터 ThreadAbortException은 더 이상 최종 실행을 방해하지 않습니다. ThreadAbortException은 이제 마지막 이전 또는 이후에 게양됩니다. 스레드 중단이 발생하기 전에 try가 실제로 입력 된 경우 마지막은 항상 실행되며 스레드 중단에 의해 중단되지 않습니다.

다음 시나리오에서는 최종적으로 실행되지 않습니다.

비동기 StackOverflowException.
.NET 2.0부터 스택 오버플로로 인해 프로세스가 종료됩니다. 마지막으로 CER (Constrained Execution Region)을 만들기 위해 추가 제한 조건이 적용되지 않는 한 마지막은 실행되지 않습니다. CER은 일반 사용자 코드에서 사용해서는 안됩니다. 모든 프로세스가 스택 오버플로에서 종료 된 후 정리 된 코드가 항상 실행되어야하는 중요한 위치에서만 사용해야하며, 따라서 모든 관리 대상 객체는 기본적으로 정리됩니다. 따라서 CER과 관련이있는 유일한 위치는 프로세스 외부에 할당 된 리소스 (예 : 관리되지 않는 핸들)입니다.

일반적으로 비 관리 코드는 사용자 코드가 사용하기 전에 일부 관리 클래스에 의해 랩핑됩니다. 관리 랩퍼 클래스는 일반적으로 SafeHandle을 사용하여 관리되지 않는 핸들을 랩합니다. SafeHandle은 중요한 종료 자 및 CER에서 실행되는 정리 메소드를 구현하여 정리 코드의 실행을 보장합니다. 이러한 이유로 CER이 사용자 코드 전체에 흩어져 있지 않아야합니다.

따라서 최종적으로 StackOverflowException에서 실행되지 않는다는 사실은 프로세스가 종료되기 때문에 사용자 코드에 영향을 미치지 않습니다. SafeHandle 또는 CriticalFinalizerObject 외부에서 관리되지 않는 리소스를 정리해야하는 경우가있는 경우 다음과 같이 CER을 사용하십시오. 관리되지 않는 개념은 설계 상 관리되는 클래스 및 적절한 SafeHandle로 추상화되어야합니다.

예를 들어

// 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.
}

다른 답변에서 언급하지 않았으며 (C #에서 18 년 동안 프로그래밍 한 후) 알지 못했던 예외는 매우 중요합니다.

블록 내부 에서 모든 종류 의 예외를 던지거나 트리거하면 catch(이상 StackOverflowExceptions하고 그 일이 아닌 것들) 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();
}

나는 이것에 대한 이유가 있다고 확신하지만 더 널리 알려지지 않은 것은 기괴합니다. ( 예를 들어 여기언급되어 있지만이 특정 질문의 어느 곳에서도 언급 되지 않았습니다.)


나는 파티에 늦었지만 실제로 MSDN 상태 ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ) 에서 예외가 발생하는 시나리오 (OP의 예와는 다름)에 있음을 알고 있습니다 . "예외가 발견되지 않으면 finally 블록의 실행은 운영 체제가 예외 해제 작업을 트리거할지 여부에 따라 결정 됩니다."

finally 블록은 Main과 같은 다른 함수가 콜 스택을 넘어서서 예외를 잡을 경우 에만 실행되도록 보장 됩니다. 모든 런타임 환경 (CLR 및 OS) C # 프로그램은 프로세스가 종료 할 때 소유하고있는 대부분의 리소스 (파일 핸들 등)에서 무료로 실행되므로이 ​​세부 사항은 일반적으로 문제가되지 않습니다. 일부 경우에는 중요 할 수 있습니다. 데이터베이스 조작이 절반 정도 진행되어 resp를 커밋하려고합니다. 풀다; 또는 OS에 의해 자동으로 닫히지 않고 서버를 차단할 수있는 일부 원격 연결.


예. 그것이 사실 마지막 진술의 요점입니다. 치명적인 일이 발생하지 않는 한 (메모리 부족, 컴퓨터 분리 등) finally 문은 항상 실행해야합니다.


또한 catch되지 않은 예외가 발생하고 Windows 서비스에서 호스팅되는 스레드에서 실행되지 않습니다.

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


System.exit (0)을 사용하여 응용 프로그램을 종료하는 경우 마지막으로 실행되지 않습니다. 에서와 같이

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

결과는 다음과 같습니다.


시나리오의 99 %가 finally블록 내부의 코드 가 실행 되도록 보장 하지만이 시나리오를 생각해보십시오 try.-> finally블록 (no catch) 이있는 스레드가 있고 해당 스레드 내에서 처리되지 않은 예외가 발생합니다. 이 경우 스레드가 종료되고 해당 finally블록이 실행되지 않습니다 (이 경우 응용 프로그램을 계속 실행할 수 있음)

이 시나리오는 매우 드물지만 대답이 항상 "예"가 아니며 대부분 "예"이고 때로는 드문 경우에는 "아니오"라는 것을 보여주기위한 것입니다.


finally 블록의 주요 목적은 그 안에 기록 된 내용을 실행하는 것입니다. try 또는 catch에서 발생하는 모든 것에 의존해서는 안되지만 System.Environment.Exit (1)을 사용하면 다음 코드 줄로 이동하지 않고 응용 프로그램이 종료됩니다.

참고 URL : https://stackoverflow.com/questions/345091/will-code-in-a-finally-statement-fire-if-i-return-a-value-in-a-try-block

반응형