문제

예외를 포착하고 다시 발생시킬 때 고려해야 할 모범 사례는 무엇입니까?나는 Exception 사물 InnerException 및 스택 추적이 유지됩니다.이를 처리하는 방식에 있어 다음 코드 블록 간에 차이가 있습니까?

try
{
    //some code
}
catch (Exception ex)
{
    throw ex;
}

대:

try
{
    //some code
}
catch
{
    throw;
}
도움이 되었습니까?

해결책

스택 추적을 보존하는 방법은 다음을 사용하는 것입니다. throw; 이것도 유효해요

try {
  // something that bombs here
} catch (Exception ex)
{
    throw;
}

throw ex; 기본적으로 해당 지점에서 예외를 발생시키는 것과 같으므로 스택 추적은 throw ex; 성명.

마이크 또한 예외를 통해 예외를 전달할 수 있다고 가정하면(권장됨) 정확합니다.

칼 세귄 가지고있다 예외 처리에 대한 훌륭한 글 그의 프로그래밍의 기초 전자책 게다가 정말 잘 읽었습니다.

편집하다:작업 링크 프로그래밍의 기초 pdf.텍스트에서 "예외"를 검색해 보세요.

다른 팁

초기 예외와 함께 새 예외가 발생하면 초기 스택 추적도 유지됩니다.

try{
} 
catch(Exception ex){
     throw new MoreDescriptiveException("here is what was happening", ex);
}

실제로는 몇 가지 상황이 있습니다. throw 명령문은 StackTrace 정보를 유지하지 않습니다.예를 들어, 아래 코드에서:

try
{
  int i = 0;
  int j = 12 / i; // Line 47
  int k = j + 1;
}
catch
{
  // do something
  // ...
  throw; // Line 54
}

StackTrace는 47행에서 예외가 발생했지만 54행에서 예외가 발생했음을 나타냅니다.

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at Program.WithThrowIncomplete() in Program.cs:line 54
   at Program.Main(String[] args) in Program.cs:line 106

위에서 설명한 것과 같은 상황에서는 원본 StackTrace를 보존하는 두 가지 옵션이 있습니다.

Exception.InternalPreserveStackTrace 호출

비공개 메서드이므로 리플렉션을 사용하여 호출해야 합니다.

private static void PreserveStackTrace(Exception exception)
{
  MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
    BindingFlags.Instance | BindingFlags.NonPublic);
  preserveStackTrace.Invoke(exception, null);
}

StackTrace 정보를 보존하기 위해 비공개 방법을 사용한다는 단점이 있습니다.이는 .NET Framework의 이후 버전에서 변경될 수 있습니다.위의 코드 예제와 아래 제안된 솔루션은 다음에서 추출되었습니다. Fabrice MARGUERIE 웹로그.

Exception.SetObjectData 호출

아래 기술은 다음과 같이 제안되었습니다. 안톤 티키 에 대한 대답으로 C#에서 스택 추적을 잃지 않고 InnerException을 다시 발생시키는 방법은 무엇입니까? 질문.

static void PreserveStackTrace (Exception e) 
{ 
  var ctx = new StreamingContext  (StreamingContextStates.CrossAppDomain) ; 
  var mgr = new ObjectManager     (null, ctx) ; 
  var si  = new SerializationInfo (e.GetType (), new FormatterConverter ()) ; 

  e.GetObjectData    (si, ctx)  ; 
  mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData 
  mgr.DoFixups       ()         ; // ObjectManager calls SetObjectData 

  // voila, e is unmodified save for _remoteStackTraceString 
} 

하지만 공개 메서드에만 의존한다는 장점이 있지만 다음 예외 생성자에도 의존합니다(제3자가 개발한 일부 예외는 구현하지 않음).

protected Exception(
    SerializationInfo info,
    StreamingContext context
)

내 상황에서는 내가 사용하고 있던 타사 라이브러리에서 발생한 예외가 이 생성자를 구현하지 않았기 때문에 첫 번째 접근 방식을 선택해야 했습니다.

때를 throw ex, 본질적으로 새로운 예외가 발생하고 원래 스택 추적 정보가 누락됩니다. throw 선호되는 방법입니다.

경험 법칙은 기본을 잡고 던지는 것을 피하는 것입니다. Exception 물체.이렇게 하면 예외에 대해 좀 더 현명해지게 됩니다.즉, 당신은 SqlException 귀하의 처리 코드가 NullReferenceException.

현실 세계에서는 잡기도 하지만 그리고 로깅 기본 예외도 좋은 습관이지만 예외를 얻으려면 모든 과정을 수행하는 것을 잊지 마십시오. InnerExceptions 그랬을 수도 있습니다.

아무도 그 차이점을 설명하지 않았습니다. ExceptionDispatchInfo.Capture( ex ).Throw() 그리고 평원 throw, 여기 있습니다.그러나 일부 사람들은 문제를 발견했습니다. throw.

잡힌 예외를 다시 발생시키는 완전한 방법은 다음을 사용하는 것입니다. ExceptionDispatchInfo.Capture( ex ).Throw() (.Net 4.5에서만 사용 가능)

이를 테스트하는 데 필요한 경우는 다음과 같습니다.

1.

void CallingMethod()
{
    //try
    {
        throw new Exception( "TEST" );
    }
    //catch
    {
    //    throw;
    }
}

2.

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch( Exception ex )
    {
        ExceptionDispatchInfo.Capture( ex ).Throw();
        throw; // So the compiler doesn't complain about methods which don't either return or throw.
    }
}

3.

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch
    {
        throw;
    }
}

4.

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch( Exception ex )
    {
        throw new Exception( "RETHROW", ex );
    }
}

사례 1과 사례 2는 소스 코드 줄 번호가 있는 스택 추적을 제공합니다. CallingMethod 메소드는 라인 번호입니다. throw new Exception( "TEST" ) 선.

그러나 사례 3에서는 소스 코드 줄 번호가 있는 스택 추적을 제공합니다. CallingMethod 메소드는 라인 번호입니다. throw 부르다.이는 다음을 의미합니다. throw new Exception( "TEST" ) 줄이 다른 작업으로 둘러싸여 있으면 실제로 예외가 발생한 줄 번호를 알 수 없습니다.

사례 4는 원래 예외의 줄 번호가 유지된다는 점에서 사례 2와 유사하지만 원래 예외의 유형을 변경하므로 실제 다시 발생은 아닙니다.

몇몇 사람들은 실제로 매우 중요한 점을 놓쳤습니다. 'throw'와 'throw ex'는 동일한 작업을 수행할 수 있지만 예외가 발생한 라인인 중요한 정보를 제공하지 않습니다.

다음 코드를 고려해보세요.

static void Main(string[] args)
{
    try
    {
        TestMe();
    }
    catch (Exception ex)
    {
        string ss = ex.ToString();
    }
}

static void TestMe()
{
    try
    {
        //here's some code that will generate an exception - line #17
    }
    catch (Exception ex)
    {
        //throw new ApplicationException(ex.ToString());
        throw ex; // line# 22
    }
}

'throw' 또는 'throw ex'를 수행하면 스택 추적을 얻을 수 있지만 라인#은 #22가 되므로 정확히 어떤 라인이 예외를 발생시켰는지 알 수 없습니다(1개 또는 몇 개만 있는 경우 제외). try 블록의 코드 줄).예외에서 예상되는 라인 #17을 얻으려면 원래 예외 스택 추적을 사용하여 새 예외를 발생시켜야 합니다.

항상 "Throw"를 사용해야합니다. .NET의 예외를 재창조하기 위해

이것을 참고하세요,http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx

기본적으로 MSIL(CIL)에는 "throw"와 "rethrow"라는 두 가지 명령이 있습니다.

  • C#의 "Throw Ex;" MSIL의 "Throw"로 컴파일됩니다.
  • C#'s "Throw"; -Sil "Rethrow"로!

기본적으로 "throw ex"가 스택 추적을 무시하는 이유를 알 수 있습니다.

다음을 사용할 수도 있습니다.

try
{
// Dangerous code
}
finally
{
// clean up, or do nothing
}

그리고 발생한 모든 예외는 이를 처리하는 다음 수준까지 버블링됩니다.

나는 확실히 다음을 사용할 것입니다 :

try
{
    //some code
}
catch
{
    //you should totally do something here, but feel free to rethrow
    //if you need to send the exception up the stack.
    throw;
}

그러면 스택이 보존됩니다.

참고로 나는 이것을 테스트하고 'Throw'로보고 된 스택 추적을 테스트했다. 완전히 올바른 스택 트레이스가 아닙니다.예:

    private void foo()
    {
        try
        {
            bar(3);
            bar(2);
            bar(1);
            bar(0);
        }
        catch(DivideByZeroException)
        {
            //log message and rethrow...
            throw;
        }
    }

    private void bar(int b)
    {
        int a = 1;
        int c = a/b;  // Generate divide by zero exception.
    }

스택 추적은 예외의 원인을 올바르게 가리키지만(보고된 줄 번호) foo()에 대해 보고된 줄 번호는 throw된 줄입니다.따라서 bar()에 대한 호출 중 어느 호출이 예외를 발생시켰는지 알 수 없습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top