지금까지 생성 된 스택 트레이스를 유지하면서 내부 예외를 어떻게 재확인 할 수 있습니까?

StackOverflow https://stackoverflow.com/questions/1009762

문제

복제 : C#에서는 스택 추적을 잃지 않고 어떻게 innerexception을 재고 할 수 있습니까?

배경 스레드에서 비동기식으로 호출하는 작업이 있습니다. 때로는 상황이 나빠집니다. 이런 일이 발생하면 TargetInvocationException을 얻는 경향이 있습니다. 내가 정말로 필요로하는 것은 TargetInvocationException의 InnereXception입니다.

    try
    {
        ReturnValue = myFunctionCall.Invoke(Target, Parameters);
    }
    catch (TargetInvocationException err)
    {
        throw err.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
}

이것은 InternalPreservestackTrace에 비해 많은주기를 낭비하지만 공개 기능에만 의존하는 이점이 있습니다. 다음은 스택 트레이스 보존 기능을위한 몇 가지 일반적인 사용 패턴입니다.

// usage (A): cross-thread invoke, messaging, custom task schedulers etc.
catch (Exception e)
{
    PreserveStackTrace (e) ;

    // store exception to be re-thrown later,
    // possibly in a different thread
    operationResult.Exception = e ;
}

// usage (B): after calling MethodInfo.Invoke() and the like
catch (TargetInvocationException tiex)
{
    PreserveStackTrace (tiex.InnerException) ;

    // unwrap TargetInvocationException, so that typed catch clauses 
    // in library/3rd-party code can work correctly;
    // new stack trace is appended to existing one
    throw tiex.InnerException ;
}

다른 팁

아니요, 불가능합니다. 당신의 유일한 진정한 기회는 권장 패턴을 따르고 적절한 상태에서 자신의 예외를 던지는 것입니다. InnerException.

편집하다

당신의 관심사가 있다면 TargetInvocationException 그리고 당신은 그것을 무시하고 싶어합니다 (내가 이것을 추천 할 수있는 것처럼 아주 잘 다른 스레드에서 실행되고 있다는 사실과 관련이 있습니다. 그렇다면 여기에 자신의 예외를 던지고 첨부하는 것을 막을 수 없습니다. InnerException ~로부터 TargetInvocationException 당신 자신으로 InnerException. 약간 냄새가 나지만 원하는 것을 성취 할 수 있습니다.

원격을 사용할 때 서버 측 스택 추적을 보존하는 데 사용되는 내부 메커니즘을 사용하여 예외에서 스택 추적을 "재설정"하는 방법이 있지만 끔찍합니다.

try
{
    // some code that throws an exception...
}
catch (Exception exception)
{
    FieldInfo remoteStackTraceString = typeof(Exception).GetField("_remoteStackTraceString", BindingFlags.Instance | BindingFlags.NonPublic);
    remoteStackTraceString.SetValue(exception, exception.StackTrace);
    throw exception;
}

이것은 원래 스택 추적을 _remoteStackTraceString 예외는 예외가 다시 열릴 때 새로 재설정 된 스택 추적에 연결되는 예외의 필드입니다.

이것은 정말로 끔찍한 해킹입니다, 그러나 그것은 당신이 원하는 것을 달성합니다. 당신은 내부에서 땜질하고 있습니다 System.Exception 따라서이 방법은이 방법이 프레임 워크의 후속 릴리스에서 중단 될 수 있습니다.

TargetInvocationException이 "쓸모없는"것이라고 생각할 수도 있지만 현실입니다. .NET이 원래 예외를 취하지 않았고 TargetInvocationException으로 래핑하여 던지는 척하지 마십시오. 정말 일어났습니다. 언젠가 TargetInvocationException을 던진 코드의 위치와 같이 그 래핑에서 나오는 정보를 원할 수도 있습니다.

당신은 그렇게 할 수 없습니다. throw 매개 변수없이 사용하지 않는 한 항상 스택 추적을 재설정하십시오. 발신자가 innerexception을 사용해야 할까봐 두려워합니다 ...

"Throw"키워드를 예외로 사용하면 항상 스택 추적이 재설정됩니다.

가장 좋은 방법은 원하는 실제 예외를 포착하고 "던지기"를 사용하는 것입니다. "Throw Ex;"대신. 또는 당신이 함께하고 싶은 innerexception과 함께 자신의 예외를 던지기 위해.

나는 당신이하고 싶은 것이 가능하다고 믿지 않습니다.

다른 사람들이 말했듯이, 예외 체인을 그대로 유지하기 위해 "던지기"키워드를 추가하지 않고 사용하십시오. 원래의 예외가 필요하다면 (그것이 의미하는 바에 따르면) 체인 끝에서 예외를 호출하여 모든 것을 시작한 예외를 얻을 수 있습니다.

.NET 4.5에서 가능합니다.

catch(Exception e)
{
   ExceptionDispatchInfo.Capture(e.InnerException).Throw();
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top