친구를위한 코드를 검토하고 있으며 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 블록이 어떻게 종료 되는지에 관계없이 명령문 코드 블록 실행을 보장하는 데 사용됩니다 .
답변
일반적으로 그렇습니다. 마지막으로 실행됩니다.
다음 세 가지 시나리오의 경우 최종적으로 항상 실행됩니다.
- 예외는 발생하지 않습니다
- 동기 예외 (정상 프로그램 흐름에서 발생하는 예외).
여기에는 System.Exception에서 파생 된 CLS 호환 예외와 System.Exception에서 파생되지 않은 CLS 비준수 예외가 포함됩니다. CLS 비준수 예외는 RuntimeWrappedException에 의해 자동으로 줄 바꿈됩니다. C #은 CLS 이외의 불만 예외를 처리 할 수 없지만 C ++와 같은 언어는 예외를 처리 할 수 있습니다. C #은 비 CLS 규격 예외를 발생시킬 수있는 언어로 작성된 코드를 호출 할 수 있습니다. - 비동기 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에 의해 자동으로 닫히지 않고 서버를 차단할 수있는 일부 원격 연결.