2009-09-02 4 views
15

using (...) 문은 try {} finally {}에 대한 구문 설탕입니다.구문 및 try-catch() 사용 - 마지막 반복?

그러나 나는 다음과 같은 아래의 using 문이있는 경우 :

using (FileStream fs = File.Open(path)) 
{ 


} 

이 지금은이 파일을 열면이 발생할 수있는 예외를 잡으려면을 (이 그것으로 인해 실패 할 수 있다는 점에서 상당히 높은 위험 코드 환경)하지만, 만약 내가 try-catch를 쓰면 반복이 아닌가? 코드가 IL로 컴파일되면 코드가 JIT 될 때 반복이 삭제 될 것이라고 가정합니다.

그러나 파일을 여는 예외를 잡아서 (그래서 내가 사용하려고하는 문장의 범위 밖에서 try-catch를 감싸 야한다) 예외를 잡아서 싶다. 블록 내부의 try-catch.

이렇게하면 CLR이 내부에서 수행하는 작업에 많은 반복을 추가하는 것처럼 보입니다. CLR은 catch 절을 추가합니까?

제 동료는 사용하는 문장이 엉망이라고 주장했는데 (단 하나의 줄이 너무 길어서 코드를 매우 빠르게 변경해야하고 코드의 다른 부분에 액세스 할 필요가 없어서 약간 길었 기 때문에 베이스). 동료는 using 문을 사용하지 않지만 using 문과 try-finally/try-catch-finally 사이에 기능상의 차이점이 있습니까? 나는 WCF 서비스가 마지막으로 값을 반환하는 것에 대해 잘 알려지지 않은 경우를 보았습니다. 해결책은 수표 블록을 사용하는 것이 었습니다. C#에서 이와 비슷한 것이 있습니까?

또 다른 참고 사항은 관리되지 않는 리소스의 IDisposale 소유자를 구현하는 모든 유형입니까? 내 친구와의 토론은 그 대답이 아니오라고 지적했다. (또한이 포럼의 사용 섹션에서 몇 가지 스레드를 읽고, 거기에 아주 좋은 지식이 있습니다.)

답변

7

정말로 원한다면 몇 가지 예외를 처리해야 할 경우 직접 패턴을 구현할 수 있습니다. 개인적으로, 나는 여전히 try/catch 블록을 사용하여 간단히 감싸는 것이 더 간단하다는 것을 알게된다.

하지만 직접 해보는 경우 제대로 처리해야합니다. Using 블록은 익명 범위 블록도 작성하므로 변수가 더 빨리 수집 할 수있게됩니다. Using 블록의 끝에 호출 된 .Dispose() 메서드는 관리되지 않는 리소스 만 정리하므로 개체가 보유한 메모리가 조금 더 늘어날 수 있습니다. 그것은 큰 관심사는 아니지만 다만 기억에 남을만한 가치가 있습니다. 그래서

, 패턴의 직접적인 적응을 할, 당신의 코드가 더 같이해야합니다 :

{ 
    FileStream fs; 
    try 
    { 
     fs = File.Open(path); 

    } 
    catch (FileNotFoundException e) { /* ... */ } 
    catch (IOException e) { /* ... */ } 
    catch (Exception e) {/* ... */} 
    finally 
    { 
     if (fs != null) fs.Dispose(); 
    } 
} 

개인적으로, 나는 UsingCatchFinally 블록을 지원하기 위해 확장보고 싶습니다. 그들은 이미 코드에 대한 변환을 수행하고 있기 때문에 훨씬 복잡해집니다.

+0

결국 지원을 사용합니까? 익명의 스코프 블록을 사용하여 어디에서 사용했는지 알 수 있습니까? 나는 이것에 대해 더 알고 싶다. 따라서 사용하는 블록 (예 : FileSream.Open())에서 파일을 열면이 예외가 발생합니다. using 문이 try/finally를 구현하는 경우 try/catch를 사용하여이를 잡아 두어야합니다. – dotnetdev

4

문 안에서 발생할 수있는 여러 가지 예외적 인 경우를 명시 적으로 처리해야하는 경우 usingtry/catch/finally으로 대체하고 마지막으로 Dispose()을 명시 적으로 호출 할 수 있습니다. 또는 using 블록 주변에 try/catch을 넣어 예외적 인 상황을 처분하지 못하게 할 수 있습니다.

내용 using은 블록 내에 예외가 발생하더라도 Dispose()가 호출되도록 보장합니다. 이는 일반적인 try/[catch]/finally 구조의 매우 제한적이고 매우 구체적인 구현입니다.

중요한 것은 이러한 옵션 중 어느 것도 실제적인 영향을 미치지 않는다는 것입니다. 필요한 것이면 읽을 수 있고 이해할 수 있고 누가 신경 써야합니까? 그것은 병목이나 아무것도 될 여분의 시도처럼 아니에요!

마지막 질문에 대답하려면 IDisposable은 반드시 구현자가 관리되지 않는 리소스를 처리한다는 것을 의미하지는 않습니다. 그것보다 훨씬 간단하고 일반적인 패턴입니다. 여기에 하나의 유용한 예입니다 :

public class Timer : IDisposable 
{ 
    internal Stopwatch _stopwatch; 
    public Timer() 
    { 
     this._stopwatch = new Stopwatch(); 
     this._stopwatch.Start(); 
    } 

    public void Dispose() 
    { 
     this._stopwatch.Stop(); 
    } 
} 

우리는 명시 적으로 시작에 의존 사용하여 호출되는 중지하지 않고 시간 일이를 사용할 수 있습니다

using(Timer timer = new Timer()) 
{ 
    //do stuff 
} 
4

사용하여 시도 - 마지막의 가장 큰 차이점은 사용하면 Dispose() 메소드 만 호출됩니다.자신 만의 블록을 구현하면 다른 로직 (예 : 로깅)을 수행 할 수 있습니다.이 로직은 사용에 포함되지 않습니다.

+0

+1 for shortness –

7

필자가 선호하는 것은 using 문을 그대로두고 try/catch로 감싸는 것입니다. 바깥 쪽 try/catch는 Dispose()를 무시하면서 관찰해야 할 예외를 잡아낼 것입니다. 이것은 호출 함수에서와 같이 다른 곳에서 try/catch를 나중에 리팩토링해야하는 경우 자신을 보호 할 추가 이점이 있습니다.

최대한 IDisposable에 관한 질문 : 누구나 어떤 이유로 든이를 구현할 수 있습니다. 관리되지 않는 리소스로 제한 될 기술적 이유는 없습니다. ( 코드의 관리되지 않는 리소스로 제한되어야하는지 여부는 다른 질문입니다).

3

using 구조는 try/finally 블록의 약자이다.

FileStream fs = null; 
try 
{ 
    fs = File.Open(path); 
    // ... 
} 
finally 
{ 
    if (fs != null) 
     fs.Dispose(); 
} 

그래서 당신은 catch 필요하지 않은 경우 using를 사용하는 것이 적절하지만, 당신이 다음 할 경우 그냥 일반 try/catch/finally를 사용한다 : 즉, 컴파일러가 생성된다.

+2

'try' /'catch'에서'using' 자체를 래핑하는 데는 아무런 문제가 없습니다. 'finally'를 보지 않고 블록이 종료 된 후에 어떤 리소스가 해제되는지 즉시 알 수 있기 때문에 'finally'보다 명확합니다. –

관련 문제