문 사용이 끝나기 전에 돌아 오면 어떻게 되나요? 처분이 호출됩니까?


115

다음 코드가 있습니다.

using(MemoryStream ms = new MemoryStream())
{
     //code
     return 0;
}

dispose()메서드는 using문 중괄호 끝에서 호출됩니다 }. 나는 이후 return의 끝나기 전에 using문, 의지 MemoryStream객체가 제대로 배치 할 수? 여기서 무슨 일이 일어나나요?


4
@JonH : 정확한 중복을 찾은 다음 투표하여이 경우 마감하십시오.
Noldorin

@Noldorin : 나는 생각하기 때문에 나는이에 속는 사람을 찾고 갔다 해야한다 이전 요청을받은,하지만 난 하나를 찾을 수 없습니다. 아직 쉬운 질문이있는 것 같아요. :)
Randolpho

@JonH 및 @Noldorin-질문이 형성 될 때 중복이 표시되었을 것입니다. "유사한 질문"을 검색합니다.이 기능은 사람들이 충분히 사용하지 않는 것 같습니다.
Adam Houldsworth

@Adam : 직접 시도해보세요. 제목을 복사 / 붙여 넣기하고 시스템에서 어떤 중복 항목이 표시되는지 확인합니다. 힌트를 드릴게요. 대답은 없습니다. Google 또는 SO 검색을 통해 검색하는 경우에도 마찬가지입니다. 이 질문 전에 묻지 않은 것 같습니다 .
Randolpho

Aaap ... 다시 가져 가겠습니다. 매우 헌신적 인 검색을 한 후 거의 중복 된 것을 찾았습니다. stackoverflow.com/questions/2641692/… 이제 질문은 완전히 다르게 질문되지만 궁극적 인 질문은 거의 동일합니다. 나는 이것이 결국 속임수라고 생각할 수 있다고 생각합니다.
Randolpho

답변:


167

네, Dispose부릅니다. using블록을 떠나는 데 걸린 수단에 관계없이 실행이 블록 범위를 벗어나는 즉시 호출됩니다 return.

@Noldorin 올바르게 사용하여 지적 하듯이 using코드 블록을 컴파일 도착 try/ finallyDispose에서 호출되는 finally블록. 예를 들어 다음 코드 :

using(MemoryStream ms = new MemoryStream())
{
     //code
     return 0;
}

효과적으로 :

MemoryStream ms = new MemoryStream();
try
{
    // code
    return 0;
}
finally
{
    ms.Dispose();
}

따라서 블록이 실행을 마친 finally후에 실행이 보장 되기 때문에 try실행 경로에 Dispose관계없이 무엇이든지 호출이 보장됩니다.

자세한 내용은 이 MSDN 문서를 참조하십시오 .

부록 : 추가
할 약간의주의 사항 : Dispose은 호출이 보장 되기 때문에 Dispose구현할 때 예외가 발생하지 않도록하는 것이 거의 항상 좋은 생각 IDisposable입니다. 불행하게도, 핵심 라이브러리의 일부 클래스가 어떻게 특정 상황에 던져 Dispose내가 당신을 찾고 있어요, WCF 서비스 참조 / 클라이언트 프록시 -라고는! -그리고 그럴 때 Dispose예외 스택 해제 중에 호출 된 경우 원래 예외를 추적하는 것이 매우 어려울 수 있습니다 . 원래 예외가 Dispose호출에 의해 생성 된 새 예외에 찬성하여 삼키기 때문입니다 . 그것은 미친 듯이 실망 스러울 수 있습니다. 아니면 그게 실망 스럽습니까? 둘 중 하나. 둘 다.


4
마지막으로 Disposein을 호출하여 try-finally 블록으로 효과적으로 컴파일 되므로 설명하는 것처럼를 효과적으로 구현 finally하고 있음을 알 수 있습니다.
Noldorin

@Noldorin : 정확히. 나는 그것에 대해 분명하게 말할 수 있다고 생각하지만. 곧 편집 ....
Randolpho

1
또한 Environment.FailFast를 사용하거나 StackOverFlowException이 발생하는 경우와 같이 finally 블록의 실행이 보장되지 않는 일부 상황이 있습니다.
Christopher McAtackney

@C. McAtackney : 또한 좋은 지적입니다. 또한 IIRC, OutOfMemoryException; 기본적으로 심각한 실행 실패로 인해 예외를 포착 할 수없는 경우 Dispose가 호출되지 않습니다. 물론 이러한 경우 프로그램은 할당 된 메모리와 함께 충돌이 보장되므로 dispose 메서드에서 파일에 쓰는 것과 같은 이상한 작업을 수행하지 않는 한 99.9 %의 경우 문제가되지 않습니다. . 치명적인 프로그램 충돌을 제외하고는 그렇습니다.
Randolpho

WCF와 함께 'using ()'문을 사용해서는 안됩니다 . 자세한 내용은 이 문서 를 참조하세요. 다음은 WCF 프록시에 사용하는 코드입니다. 'WCFProxy variableName = null; try {variableName = new WCFProxy (); // 여기에 TODO 코드가 있습니다. variableName.Proxy.Close (); variableName.Dispose (); } catch (예외) {if (variableName! = null && variableName.Proxy! = null) {variableName.Proxy.Abort (); } 던져; } '
Dave Black

18

using문은 try ... finally블록 과 똑같이 동작 하므로 항상 모든 코드 종료 경로에서 실행됩니다. 그러나 나는 그들이 finally블록이 호출되지 않는 매우 드문 상황에 처해 있다고 믿습니다 . 내가 기억할 수있는 한 가지 예는 백그라운드 스레드가 활성화 된 동안 포 그라운드 스레드가 종료되는 경우입니다. GC를 제외한 모든 스레드가 일시 중지되어 finally블록이 실행되지 않습니다.

명백한 편집 : IDisposable 개체를 처리 할 수있는 논리를 제외하고는 동일하게 동작합니다.

보너스 내용 : 스택 가능 (유형이 다른 경우) :

using (SqlConnection conn = new SqlConnection("string"))
using (SqlCommand comm = new SqlCommand("", conn))
{

}

또한 쉼표로 구분 (유형이 동일한 경우) :

using (SqlCommand comm = new SqlCommand("", conn), 
       SqlCommand comm2 = new SqlCommand("", conn))
{

}



0

컴파일 한 후 리플렉터에서 코드를 살펴보십시오. 컴파일러가 코드를 리팩토링하여 dispose가 스트림에서 호출되도록합니다.

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