2011-03-29 4 views
1

예외를 그룹화하여 .NET 응용 프로그램 로깅을 향상시키고 자합니다. 이상적으로는 코드에서 발생한 위치와 예외 유형을 그룹화하는 것이 좋습니다. 그래서 본질적으로 우리는 각각의 예외 (날짜, 서버 변수 등이 다름)의 발생 목록을 작성하게 될 것입니다..NET 예외를 고유하게 식별

예를 들어 내 참조 페이지에서 5 회의 null 참조 예외를 발생시킨 메소드를 사용하는 경우 해당 예외를 한 번만 5 번 반복하여 나열합니다. 다른 페이지에 던져지고있는 또 다른 null 참조 예외가 별도로 나열됩니다.

stacktrace를 사용하여 예외를 확실하게 식별 할 수 있습니까? 아니면 내가 놓친 다른 것이 있습니까?

+0

왜 스택 트레이스를 필요합니까? 이름만으로 그걸 알아낼 수 없습니까? 아니면 내가 여기서 당신의 요점을 놓치고 있습니까? – Adi

+0

은 예제를 추가하여 희망적으로 자신을 명확하게 만듭니다. –

답변

4

예외가 포착 된 다음 다시 throw되면 예외가 원래 위치가 아닌 재실행 시점에서 발생한 것처럼 스택 추적이 나타납니다. 바라건대, 당신의 코드에서 그렇게 많은 것들이 진행되지는 않을 것입니다. 그렇지 않으면 스택 추적만으로 예외 위치를 구별 할 수 있습니다.

또 다른 문제점은 스택 추적이 동일하여 실제적으로 동일 할 때 두 가지 예외가 아닌 것처럼 보일지 여부입니다. 스택 트레이스는 내 경험상 동일하기 때문에 문제가 될 수 없습니다. (예외 오브젝트에 있으며, toString() 결과는 일반적으로 동일하지 않습니다.)

상황이 Exception.StackTrace가 손상 될 것입니다 정확히 무엇에 대한 몇 가지 논란이 있었다 업데이트되었습니다. 기본 규칙은 언제든지

throw *expression*; 

*expression* 식별이 StackTrace 속성 집합있을 것이라는 점을 다음 Exception 객체를 실행한다는 것입니다. *expression*이 생략 된 경우

throw; 

그러면 StackTrace가 적용되지 않습니다.

이 두 형식의 용어를 찾을 수 없으므로 각 형식을 "명시 적"및 "암시 적"이라고 각각 부릅니다. *expression*이 해결하는 예외 개체가 new인지 또는 이미 존재하는 개체인지 여부는 중요하지 않습니다.여기

이 동작을 설명하기위한 프로그램이다

using System; 
namespace FunWithExceptions 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      try { Replace(); } 
      catch (InvalidOperationException ex) { DisplayResult("Replace resulted in", ex); } 

      try { RethrowExplicit(); } 
      catch (InvalidOperationException ex) { DisplayResult("RethrowExplicit resulted in", ex); } 

      try { RethrowImplicit(); } 
      catch (InvalidOperationException ex) { DisplayResult("RethrowImplicit resulted in", ex); } 

      InvalidOperationException myException = new InvalidOperationException(); 
      DisplayResult("myException starts with", myException); 
      try { throw myException; } 
      catch (InvalidOperationException) { } 
      DisplayResult("myException changes to", myException); 
      Console.ReadLine(); 
     } 

     static void ThrowAnException() 
     { throw new InvalidOperationException("You messed up!"); } 

     static void Replace() 
     { 
      try { ThrowAnException(); } 
      catch (InvalidOperationException ex) 
      { 
       DisplayResult("Replace caught", ex); 
       throw new InvalidOperationException("Another mistake."); 
      } 
     } 

     static void RethrowExplicit() 
     { 
      try { ThrowAnException(); } 
      catch (InvalidOperationException ex) 
      { 
       DisplayResult("RethrowExplicit caught", ex); 
       throw ex; 
      } 
     } 

     static void RethrowImplicit() 
     { 
      try { ThrowAnException(); } 
      catch (InvalidOperationException ex) 
      { 
       DisplayResult("RethrowImplicit caught", ex); 
       throw; 
      } 
     } 

     static void DisplayResult(string context, Exception ex) 
     { 
      Console.WriteLine("{0} exception thrown at {1}", context, FirstMethodName(ex.StackTrace)); 
     } 

     private const string methodNamePrefix = " at FunWithExceptions.Program."; 

     private static object FirstMethodName(string stackTrace) 
     { 
      stackTrace = stackTrace ?? string.Empty; 
      if (stackTrace.StartsWith(methodNamePrefix)) 
       stackTrace = stackTrace.Substring(methodNamePrefix.Length); 
      int methodNameEndIndex = stackTrace.IndexOf(')'); 
      if (methodNameEndIndex != -1) 
       stackTrace = stackTrace.Substring(0, methodNameEndIndex + 1); 
      if (stackTrace.Length > 0) 
       return stackTrace; 
      else 
       return "--empty--"; 
     } 
    } 
} 

다음 출력 결과를이 프로그램 :

하는 ThrowAnException (던져 잡힌 예외)

바꾸기 예외 결과 바꾸기 Replace()에서 throw 됨

RethrowExplicit catch throw 예외 : ThrowAnException()

RethrowExplicit는 RethrowExplicit 던져 예외()

RethrowImplicit가 ThrowAnException 던져 예외() 결과 ThrowAnException()에서 발생 RethrowImplicit 잡힌 예외

myException 슬로우 예외 시작 초래 at --empty--

메인에서 예외가 변경됨 (String [] args)

6 번째 줄이 흥미 롭습니다.

저기, 나는이 시점에서 완전히 죽음에 이릅니다. :-)

+0

* "예외가 잡힌 다음 다시 throw 된 경우 스택 추적은 예외가 원래 위치가 아닌 재실행 시점에서 발생하는 것처럼 보입니다."* - 'throw'를 사용하지 않고'throw ex ; ' –

+0

@ Maxim Gueivandov - 예, 그것이 제가 의미했던 것입니다. (당신이 @ChrisF에 대한 제 코멘트에서 볼 수 있듯이) 제 생각에는 제쳐두고 간결하게하려고했습니다. –

+0

awesome answer mate, thanks heaps –

1

예외를 삼키지 않은 상태에서 새로운 예외를 던지면 (아래의 잘못된 예와 같이) 괜찮을 것입니다. 예외를 던지는 원의 예외의 스택 트레이스를 대체로

try 
{ 
    ... your code 
} 
catch (ExceptionA exA) 
{ 
    ... some error handling 
    throw new ExceptionZ(); 
} 
catch (ExceptionB exB) 
{ 
    ... some error handling 
    throw new ExceptionZ(); 
} 

이 코드는이 인스턴스에 나쁘다. 어쨌든 일반적으로 좋은 습관은 아니지만이 경우 예외를 찾아 고유하게 기록하는 것을 막을 수 있습니다.

+0

'throw new ExceptionZ();'가 아닌 'throw exA;'가 스택 추적을 대체 할 것이라는 것에주의하십시오. 예외 객체가 지정되지 않은 상태에서'throw;'만이 catch-and-throw scenerio에서 스택 추적을 보존합니다. –

+0

@ 제프리 - 그건 제가 지적했습니다. 나는 그것을 분명히 할 것이다. – ChrisF

+0

나는 별개의 지점을 만들고 있었지만, 지금 당신의 교정은 잘못된 답을 만들었습니다! 예외 객체 ('new 또는 old)를 던지면 그 예외에 대한 스택 추적이 설정됩니다. –

0

예에서 (그리고 대부분의 경우 실제로) 널값에 따라 다른 예외 유형이 발생했습니다. 이러한 예외를 포착하는 코드는 필요한 데이터를 기록 할 수 있습니다.

1

좋아, 그래서 기본적으로 안정적으로 예외 예외 PLUS 위치를 식별하고 싶습니다. 스택 추적이 나에게 좋을 것 같습니다. 은 그러나 당신은 또한, 사용자의 위치 식별 당신은 생성자에서 GetCurrentMethod()를 호출하고 읽기 전용 속성을 통해 메소드 이름을 노출하는 기본 예외에서 모든 예외 유형을 도출 할 수있는 방법이 이름

System.Reflection.MethodBase.GetCurrentMethod() 

를 사용하여 기반으로 할 수 있습니다 그래서 어디에서 예외가 발생했는지 어디에서 알 수 있습니까?

예 :

public class BaseException : ApplicationException { 
    public BaseException() { 
     _originalMethod = System.Reflection.MethodBase.GetCurrentMethod().Name; 
    } 
    private string _originalMethod; 
    public string OriginalMethod { get { return _originalMethod; } } 
} 

//now, create tons of custom exceptions: 
public class MyException1 : BaseException { 
    public MyException1() 
     : base() { 
    } 
} 
//create more custom exceptions... 
public class MyExceptionNNN : BaseException { 
    public MyExceptionNNN() 
     : base() { 
    } 
} 
+0

null 참조 예외 (OP의 예)는 사용자 정의 예외 기본 클래스를 사용하지 않습니다.또, throw 메소드가 많은 장소로부터 불려 갔을 경우, 메소드 명 만이 사용되고있는 경우는, 예외가 복수의 원인이 같아 보이는 경우가 있습니다. –

관련 문제