2009-04-04 5 views
13

내가 두 개의 서로 다른 어셈블리에 다음과 같은 두 개의 클래스가 있다고 가정 :매개 변수가없는 catch를 다시 던지는 것과 아무 것도하지 않는 것의 차이점은 무엇입니까?

이 경우
//in assembly A 
public class TypeA { 
    // Constructor omitted 
    public void MethodA 
    { 
    try { 
     //do something 
    } 
    catch { 
     throw; 
    } 
    } 
} 
//in assembly B 
public class TypeB { 
    public void MethodB 
    { 
    try { 
     TypeA a = new TypeA(); 
     a.MethodA(); 
    } 
    catch (Exception e) 
     //Handle exception 
    } 
    } 
} 

, MethodA의 시도 - 캐치 그냥 예외를 올리고 있지만, 정말 처리하지 않습니다. MethodA에서 try-catch를 사용하는 데 어떤 이점이 있습니까? 즉, 이런 유형의 try-catch 블록과 전혀 사용하지 않는 블록 사이에는 차이점이 있습니까?

+0

try catch 잡기에 도움이되는 디버깅에 도움이됩니다. 응용 프로그램이 어떤 식 으로든 완료 될 때 많은 예외가 발생할 수 있습니다. (언급 된 리소스 문제) – bytebender

답변

7

귀하의 경우에는 이점이 없습니다. 그러나 특정 예외를 버블 링하는 것이 바람직 할 경우가 있습니다.

public void Foo() 
    { 
     try 
     { 
      // Some service adapter code 

      // A call to the service 
     } 
     catch (ServiceBoundaryException) 
     { 
      throw; 
     } 
     catch (Exception ex) 
     { 
      throw new AdapterBoundaryException("some message", ex); 
     } 
    } 

이 쉽게 예외가 발생, 경계를 식별 할 수 있습니다.이 경우, 당신은 당신의 경계 예외가 단지 경계에 특정 코드를 던져 확인해야합니다.

+0

... 코드가 핫 경로에 있거나 심하게 재귀 적이기 때문에 예외가 반복해서 다시 throw됩니다. http://blogs.msdn.com/curth/archive/2008/07/29/stackoverflowexception- and-ironpython.aspx –

2

코드를 사용하여 MethodA에 대해 작성한 방법과 차이는 없습니다. 프로세서 사이클을 먹어 치울뿐입니다. 그러나 무료로 제공해야하는 리소스가 있으면이 방법으로 코드를 작성하는 것이 이점이 될 수 있습니다. 예 :

Resource r = GetSomeResource(); 
try { 
    // Do Something 
} catch { 
    FreeSomeResource(); 
    throw; 
} 
FreeSomeResource(); 

그러나 이렇게하는 데는 실제 포인트가 없습니다. 많이 그냥 대신 finally 블록을 사용하는 것이 좋습니다.

+0

finally 블록을 사용하는 것이 더 낫습니다. 부울 플래그 변수, 추한대로. CIL에는 실제로이 작업을 수행하는 오류 처리기가 있지만 일부 알 수없는 이유로 C#에서는 오류를 표시하지 않습니다. –

+0

@Anton, hah, C++ 질문으로 읽었습니다. – JaredPar

+0

이 기술은 함수에서 자원을 반환 할 계획 인 경우 유용합니다. 예외로 인해 계획이 무효화되므로 예외가 전파되도록 허용하기 전에 함수 자체에서 리소스를 정리해야합니다. –

1

그냥 재검토해도 말이되지 않습니다. 아무 것도하지 않은 것과 같습니다.

실제로 뭔가를 할 때 유용하지만 가장 일반적인 것은 예외를 기록하는 것입니다. 클래스의 상태를 변경할 수도 있습니다.

3

예 차이가 있습니다. 예외를 잡았을 때 .NET은 어떤 방식 으로든 처리 할 것으로 가정하고 스택은 catch를 수행하는 함수까지 풀립니다.

catch하지 않으면 디버거 나 예외 로거와 같은 일종의 진단을 호출하는 처리되지 않은 예외로 끝날 수 있습니다. 전체 스택과 실제 실패 지점의 상태는 다음과 같습니다. 검사 가능.

그래서 다른 곳에서 처리되지 않은 예외를 다시 잡아 당겨 실제로 진단 된 유용한 정보를 진단 도구에서 빼내십시오.

+0

흠, 이것은 미묘합니다.다른 예외를 다시 던지면 명시 적으로 보존하지 않으면 스택 추적이 손실되지만 원래 예외 ('throw;')를 다시 throw하면 스택 추적이 보존됩니다. –

+0

안토니, 네 생각이 틀렸어. http://blog.dotnetclr.com/archive/2007/11/05/Re-throwing-an-exception.aspx –

+0

좋아요, 제 표현은 충분히 정확하지 않았습니다 :'던지기'와'던지기'*는 * 다른, 그리고 둘 다 "원래의 예외를 제하기"라고 말할 수 있지만, 나는'throw; '라고 쓰고, 당신의 링크는 (링크 된 포스트의 끝 바로 전에) 동의합니다. –

1

옵션을 사용하지 마십시오. A. Anton가 말한 것처럼 스택 추적을 처리합니다. JaredPar의 예는 스택 추적도 가져옵니다. 더 나은 솔루션은 다음과 같습니다

SomeType* pValue = GetValue(); 
try { 
    // Do Something 
} finally { 
    delete pValue; 
} 

당신은 예를 들어, 출시 될 다음과 같은 두 가지 선택이있어하여 FileStream 필요가 C#에서 뭔가를 가지고있는 경우 :

FileStream stream; 
try 
{ 
    stream = new FileStream("C:\\afile.txt"); 
    // do something with the stream 
} 
finally 
{ 
    // Will always close the stream, even if there are an exception 
    stream.Close(); 
} 

또는 더 깨끗하게 :

using (FileStream stream = new FileStream("c:\\afile.txt")) 
{ 
    // do something with the stream 
} 

문을 사용하면 완료되거나 예외가 닫히면 스트림을 삭제하고 닫을 수 있습니다.

+0

스택 트레이스가 아니라 스택 공간에 대해 이야기하고있었습니다. 스택 추적은 원래의 예외를 재실행하는 특별한 경우에 OK입니다. –

+2

Jared의 코드는 스택 추적을 파괴하지 않습니다. 스택 추적에는 여전히 예외의 원본 소스가 표시됩니다. 매개 변수로 예외를 잡아 내고 캐치 된 예외를 새로 던지는 것을 혼란스럽게합니다. "catch (Exception e) {throw e;}"- 스택 추적을 삭제합니다. –

1

catch하고 throw 할 때 throw 줄에 중단 점을 설정할 수 있습니다.

+0

디버거가 예외를 위반할 수 있습니다. 중단 점에 대해서만이 작업을 수행하지 마십시오. 이 코드는 그런 식으로 발송 될 가능성이 높습니다. –

+0

예외가 발생하면 중단 점이있는 프로 시저를 중단하는 것과 동일하지 않습니다. 게다가 그 질문은 좋은 생각인지 묻지 않았다. 그것은 그 효과가 무엇인지 물었다. –

+0

@ Rob : 나는 John과 동의한다. 이것은 좋은 생각이 아니다. – AnthonyWJones

1

재실행 예외는 다음 예제처럼 일반적인 예외로 캡슐화하는 데 사용할 수 있습니다.

public class XmlException: Exception{ 
    .... 
} 

public class XmlParser{ 
    public void Parse() 
    { 
     try{ 
      .... 
     } 
     catch(IOException ex) 
     { 
     throw new XmlException("IO Error while Parsing", ex); 
     } 
    } 
} 

이렇게하면 예외를 분류하는 것보다 이점이 있습니다. 이것은 aspx 파일 핸들러와 다른 많은 시스템 코드가 예외적 인 캡슐화를 수행하여 스택 및 로직 흐름을 결정합니다.

+0

당신이 대답 한 질문은 Cullen이 묻지 않은 질문입니다. –

3

첫 번째 옵션은 나쁨 (또는 '쓸모없는'것이어야합니까?) 아이디어처럼 보일 것입니다. 그러나이 방법은 거의 없습니다. 예외는 일반적으로 두 가지 조건, 즉

a 아래에서 Catch 블록 내에서 다시 던집니다. 데이터에 대해 생성 된 예외를 확인하고 스택을 조건부로 버블 링하려고합니다.

try 
{ 
    //do something 
} 
catch (Exception ex) 
{ 
    //Check ex for certain conditions. 
    if (ex.Message = "Something bad") 
    throw ex; 
    else 
    //Handle the exception here itself. 
} 

b. 구성 요소 내에서 허용 할 수없는 조건이 발생했으며이 정보를 호출 코드에 전달해야합니다 (일반적으로 다른 유용한 정보를 추가하거나 다른 예외 유형으로 모두 묶음).

try 
{ 
    //do something 
} 
catch (StackOverflowException ex) 
{ 
    //Bubble up the exception to calling code 
    //by wrapping it up in a custom exception. 
    throw new MyEuphemisticException(ex, "Something not-so-good just happened!"); 
} 
+1

"throw ex"가 좋지 않습니다 - 스택 위로 나사를 조이십시오. 그냥 "던져" –

+0

정말 StackOverflowException 잡을 수있어? .NET 2.0 이상에서는 그렇게 할 수 없다고 생각했습니다. –

+2

조건부 논리의 예외 메시지 속성을 현지화 할 수 있으므로 사용하지 마십시오. –

1

어셈블리 A - try 캐치 블록은 나에게 이해가 가지 않습니다. 나는 당신이 예외를 처리하지 않는다면, 왜 당신은 그 예외들을 잡는가? 그것은 어쨌든 다음 단계로 넘어갈 것입니다.

중간 계층 API 또는 이와 비슷한 것을 작성하고 해당 계층에서 예외를 처리하면 (예외가 발생 함) 해당 계층이 의미가 없으면 ApplicationException 예외를 던질 수 있습니다. 그러나 확실히 똑같은 예외를 되 돌리는 것은 의미가 없습니다.

1

클래스가 2 개의 다른 어셈블리에 있기 때문에, 단순히 클래스를 로깅하기위한 예외를 잡아서 호출자에게 던져서 적합하다고 생각되는 방식으로 처리 할 수 ​​있습니다. throw ex 대신에 throw를 사용하면 (자), 예외의 발생원에 관한 문맥 정보가 보관 유지됩니다. 이것은 어셈블리가 API/프레임 워크 인 경우에 유용합니다. 예를 들어 EventLog에 기록되는 경우 문제 해결에 도움이되지만 의미있는 것이 아니라면 예외를 삼켜서는 안됩니다.

0

Method A에서 try {} catch (ex) {} 블록을 사용할 수 있습니다 (예 : 로깅의 경우).

또 다른 옵션은 InnerException 속성을 사용하여 호출자에게 전달하는 예외 체인입니다. 이 아이디어는 스택 추적을 죽이지 않습니다.