2012-10-01 3 views
4

"순수하게 문서화"목적으로 메서드에서 예외를 잡아서 메서드 자체 안에 오류 문서를 캡슐화하거나 호출자의 책임입니까?"순수하게 문서화하는"목적으로 내 메서드에서 예외를 잡아야합니까?

EncryptPackage() 메서드에서 여러 가지 예외를 throw 할 수있는 프레임 워크를 비롯하여 수많은 다른 메서드를 호출한다고 가정합니다. 나는 using 블럭의 모든 것을 덮어 쓴다. 그래서 클린업을위한 예외를 잡을 필요가 없다. (또는 나는 try/finally를 사용한다.) 어쨌든 예외를 catch해야하고 해당 메서드의 컨텍스트에 대한 세부 정보를 제공해야합니까? 아니면 호출자 메서드의 책임입니까? 하는과, 그냥 "오류 텍스트를 장식하는"하려면 EncryptPackage() 방법은 가능한 모든 예외를 잡는다 방법 텍스트를 "오류 패키지를 암호화하는 동안 발생했습니다"알

[Serializable] 
class TestClassException : Exception 
{ 
    public TestClassException() : base() { } 
    public TestClassException(string message) : base(message) { } 
    public TestClassException(string message, Exception innerException) : base(message, innerException) { } 
} 

class TestClass 
{ 
    public TestClass() { } 

    public void EncryptPackage() 
    { 
     try 
     { 
      DoSomething(); 
      DoAnotherThing(); 
     } 
     catch (Exception ex) 
     { 
      throw new TestClassException("Error occurred during package encryption", ex); 
     } 
    } 
} 

class ConsumerExample 
{ 
    public ConsumerExample() { } 

    public void DoSomeStuff() 
    { 
     TestClass testClass = new TestClass(); 

     try 
     { 
      testClass.EncryptPackage(); 
     } 
     catch (TestClassException ex) 
     { 
      System.Windows.Forms.MessageBox.Show(ex.ToString()); 
     } 
    } 
} 

이 코드에서 : 여기

는 경우입니다 . 여기서 EncryptPackage()은 오류 설명 논리를 캡슐화합니다. 여기

그리고

이 또 다른 기술이다. 호출자가 오류 패키지 암호화 동안 오류가 발생했습니다 "로 어쨌든 오류 사례를 문서화하기 때문에,이 예에서

class TestClass2 
{ 
    public TestClass2() { } 

    public void EncryptPackage() 
    { 
     DoSomething(); 
     DoAnotherThing(); 
    } 
} 

class ConsumerExample2 
{ 
    public ConsumerExample2() { } 

    public void DoSomeStuff() 
    { 
     TestClass testClass = new TestClass(); 

     try 
     { 
      testClass.EncryptPackage(); 
     } 
     catch (Exception ex) 
     { 
      System.Windows.Forms.MessageBox.Show("Error occurred during package encryption.\r\n\r\n" + ex.ToString()); 
     } 
    } 
} 

, EncryptPackage() 아무것도 캐치하지 않았던 \ 연구 \ 없음 \ 연구 \ n "메시지.

이것은 매우 단순한 예이며 실제로는 수많은 계층 적 클래스가있을 것이고 예외는 긴 호출 스택을 통해 전파되므로 예외를 잡는 방법이 선호됩니까? 두 번째 접근법은 예외가 "실제 처리"(예 : 사용자에게 표시)가 수행되는 계층에서 처리되기 때문에 "보다 명확하게"보입니다. 호출 스택 정보는 예외 객체에 보존되므로 기술적으로 예외가 발생한 정확한 위치를 찾을 수 있습니다. 하지만 ... 각 접근 수준이 오류에 자체 설명을 추가하고 이전 예외가있는 innerException 멤버를 유지하는 첫 번째 접근 방식으로는 "잘 문서화 된"것으로 보이지 않습니다. 이 경우 실행시 TestClass 계층을 벗어나면 이미 내에 발생한 오류에 대한 자세한 설명이 포함되어 있습니다. 따라서 이것은 오류 처리 로직을보다 잘 캡슐화하는 것으로 느껴집니다.

어느 것을 사용할 것입니까?

+5

사람들이 나를 도우려는 경우 이전 질문에 대한 답변을 더 받아야합니까? 예. – Cephalopod

+1

'throw new TestClassException ("패키지 암호화 도중 오류가 발생했습니다", 예); 이것은 당신이 이미 해결할 수 없다는 것을 알려줍니까? –

+1

@Arian, LOL 맞아, 종종 모든 대답을 검토하고 "우승자"를 선택하는 것을 잊어 버립니다. 죄송합니다. 내 모든 질문을 지금 검토하겠습니다. 상기시켜 줘서 고마워! –

답변

1

@Sjoerd에 따라 예외를 변환하여 동일한 추상화 수준에 있도록하십시오. 귀하의 경우 EncryptPackage는 호출자가 아닌 모든 하위 수준의 예외 자체를 번역해야합니다.

저수준 예외가 DB 레이어 (예 : DBException)에 있다고 가정 해보십시오. 호출자가 DBException을 이해할 것으로 기대합니까? 대답은 NO입니다. 호출자는 DBException이 아닌 패키지를 encr하고 싶습니다. 하위 수준의 예외는 디버깅을 목적으로 높은 수준의 예외 내부에서 체인화되어야합니다.

마지막으로, TestClassException이 예제이지만 예외 클래스가 문제를 명확하게 설명하는지 확인합니다. 개인적으로는 부드럽고 일반적인 예외 클래스가 싫습니다 (다른 예외에 대한 공통 기본 클래스 제외) .

4

chapter on this in Effective Java 있습니다 :

높은 층은 낮은 수준의 예외를 포착해야하고, 자신의 자리에서, 더 높은 수준의 추상화의 관점에서 설명 될 수있다 던져 예외. 이 관용구를 예외 번역이라고합니다.

+0

질문은 다음과 같습니다. 누가 예외를 번역해야합니까? 'EncryptPackage()'가 할 것인가? 아니면 호출자가 그것을해야 하는가? –

2

주로 두 번째 예제를 선호합니다. 특히 사용자 정의 예외를 작성하는 경우 특히 오류 처리 코드의 양을 현저히 줄일 수 있기 때문에 두 번째 예제를 선호합니다. 첫 번째 예제에서는 많은 사용자 정의 많은 이점을주지 않는 예외 클래스 (이미 예외가 발생한 곳을 알려주는 호출 스택이 있음).

더 자세한 설명이 포함 된 오류 메시지를 작성하는 것이 좋겠다고 생각할 수도 있지만 누가 이점을 누릴 수 있습니까? 최종 사용자입니까? 사용자에게 예외 메시지를 표시해야합니까 (그리고 어떤 언어를 사용할 것입니까?)? 사용자가 내부 오류가 있음을 알아야 할 때가 많으며 포기 (다시 시작)하거나 다시 시도해야하는 경우가 많습니다.개발자에게 이익이됩니까? 어쨌든 호출 스택을 여러분 앞에있는 소스 코드로 검사하게 될 것입니다. 그래서 더 자세한 설명 메시지가 필요 없으므로, 그 시점에서 코드가 무엇을하는지 직접 볼 수 있습니다.

이것은 어렵지 않고 빠른 규칙이 아닙니다. 대부분 나는 예외를 상위 레벨에서만 잡아서 로그에 기록하고 사용자에게 오류를보고합니다. 예외를 사용자에게 직접보고하는 경우 원래 예외는 번역에서 이익을 얻지 못하는 경우가 많습니다. 예를 들어 존재하지 않는 파일을 열려고하면 System.IO.FileNotFoundException이 충분히 설명력이있는 이유는 무엇입니까? 다른 것? 같은 판결의 전화를하고 싶습니다 ("도서관 사서보다 잘 알고 있으므로 신중하게 만들어진 예외를 번역 할 것입니다"). 나는 (일반적으로 가능하지 않다면) 그것들을 복구하기를 원한다면 더 낮은 예외를 잡는다. 또는 매우 드물게, 나는 그것들을보다 기술적 인 예외로 번역하고 싶다.

계층 구조에서는 레이어간에 예외를 변환하는 것이 가능합니다. 예를 들어 데이터 액세스 계층에서 응용 프로그램 계층에 적합한 형식으로 예외를 catch하고 응용 프로그램 계층과 사용자 인터페이스간에 유사하게 예외를 catch하는 것이 좋습니다 ,하지만 당신이 그런 종류의 시스템에서 일하고 있는지 나는 모른다.

예외를 문서화하려면 메서드에 대한 xml 설명서에서 exception tag을 사용해야합니다. 그러면 문서의 일반적인 도움말 파일 (예 : SandCastle)을 사용할 수 있습니다.

0

당신은 몇 가지 쉽게 구별 상황에서 try/catch를 사용한다 :

  • 같은 앱의 진입 점, UI 이벤트, 멀티 스레드 전화 등으로 "외부"호출 할 수있는 방법을. 가지고있는 모든 잡다한 물건에 대해 로그 출력이나 메시지를 넣으십시오. 이렇게하면 앱이 충돌하는 것을 방지 할 수있을뿐 아니라 문제 해결 방법에 대한 피드백을 사용자에게 제공 할 수 있습니다.

  • 예외를 실제로 처리 할 수 ​​있습니다. 즉, 응용 프로그램에서 보조 데이터베이스 또는 서버 URL을 선택하고 다른 처리 방법을 적용 할 수 있음을 의미합니다.

  • 임시 워크 플로를 망가 뜨리지 않도록하려는 경우 (예 : 임시 파일 삭제 실패) 프로세스가 실패하지 않아야합니다.

  • 아마

항상 괜찮은 로깅 방법 및/또는 사용자 메시징, 돈과 오류 처리를 결합 당신이 시도/캐치를해야하지만, 이러한 드문해야 다른 장소가있다 어떤 예외 정보도 사라지게됩니다. 그것이 앱을 얻는 방법이고 "뚜렷한 이유가 없음"으로 잘 작동하지 않기 때문입니다. 적어도 이유는 명백해야합니다.

또한 예외를 사용하여 워크 플로를 제어하지 마십시오. 뭔가를하는 절대적으로 다른 방법이 없다면 정말로 "던지기"가 있어서는 안됩니다.

관련 문제