C #에서 예외가 발생하면 내부 예외가있을 수 있습니다. 내가 원하는 것은 가장 안쪽의 예외, 즉 내부 예외가없는 리프 예외를 얻는 것입니다. while 루프에서이 작업을 수행 할 수 있습니다.
while (e.InnerException != null)
{
e = e.InnerException;
}
그러나 나는 이것을 대신 사용할 수있는 한 줄짜리가 있는지 궁금했습니다.
C #에서 예외가 발생하면 내부 예외가있을 수 있습니다. 내가 원하는 것은 가장 안쪽의 예외, 즉 내부 예외가없는 리프 예외를 얻는 것입니다. while 루프에서이 작업을 수행 할 수 있습니다.
while (e.InnerException != null)
{
e = e.InnerException;
}
그러나 나는 이것을 대신 사용할 수있는 한 줄짜리가 있는지 궁금했습니다.
LINQ
루프를 작성해야 할 때 이상하게 보일 정도로 거의 모든 것을 사용 하는 데 너무 익숙해졌습니다 . 저는 주로 데이터 액세스로 작업하므로 ICollections
거의 모든 작업을 수행합니다.
LINQ
코드가 여전히 본질적으로 반복되어야한다는 사실을 마스킹 하지 않습니까? .NET에 진정한 세트 기반 명령이 있습니까?
답변:
Exception.GetBaseException()
나를 위해 그렇지 않았습니다.
나는 Exception.GetBaseException()
이러한 솔루션과 동일한 일을 한다고 생각 합니다.
주의 사항 : 다양한 의견을 통해 우리는 항상 문자 그대로 같은 일을 . 어떤 경우에는 재귀 / 반복 솔루션이 더 입니다. 그것은이다 일반적으로 , 기본을 무시 예외 특정 유형의 덕분에 실망 일관성이 가장 안쪽의 예외입니다. 그러나 특정 유형의 예외를 포착하고 (AggregateException과 같은) 이상한 것이 아닌지 합리적으로 확인하면 합법적 인 가장 안쪽 / 가장 빠른 예외가 발생할 것으로 예상합니다.
GetBaseException()
첫 번째 루트 예외를 반환하지 않았습니다.
GetBaseException()
가장 중요한 예외는 AggregateException이기 때문에 나를 위해 작동하지 않았습니다.
InnerExceptions를 통해 반복하는 것이 유일한 신뢰할 수있는 방법입니다.
발견 된 예외가 AggregateException이면 GetBaseException()
가장 안쪽에있는 AggregateException 만 반환합니다.
http://msdn.microsoft.com/en-us/library/system.aggregateexception.getbaseexception.aspx
내부 예외가 얼마나 깊이 중첩되어 있는지 모르는 경우 루프 또는 재귀를 피할 방법이 없습니다.
물론이를 추상화하는 확장 메서드를 정의 할 수 있습니다.
public static class ExceptionExtensions
{
public static Exception GetInnermostException(this Exception e)
{
if (e == null)
{
throw new ArgumentNullException("e");
}
while (e.InnerException != null)
{
e = e.InnerException;
}
return e;
}
}
나는 이것이 오래된 게시물이라는 것을 알고 있지만 아무도 수업 GetBaseException()
의 방법을 제안하지 않은 것에 놀랐습니다 Exception
.
catch (Exception x)
{
var baseException = x.GetBaseException();
}
이것은 .NET 1.1 이후로 발생했습니다. 문서 : http://msdn.microsoft.com/en-us/library/system.exception.getbaseexception(v=vs.71).aspx
사실 아주 간단합니다. Exception.GetBaseException()
Try
//Your code
Catch ex As Exception
MessageBox.Show(ex.GetBaseException().Message, My.Settings.MsgBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error);
End Try
반복해야하고 반복해야하므로 루프를 별도의 기능으로 이동하는 것이 더 깔끔합니다.
이를 처리하기 위해 확장 방법을 만들었습니다. 지정된 유형의 모든 내부 예외 목록을 반환하여 Exception.InnerException 및 AggregateException.InnerExceptions를 추적합니다.
내 특정 문제에서 내부 예외를 추적하는 것은 평소보다 더 복잡했습니다. 왜냐하면 리플렉션을 통해 호출되는 클래스의 생성자에 의해 예외가 발생했기 때문입니다. 우리가 잡은 예외에는 TargetInvocationException 유형의 InnerException이 있었고 실제로 살펴 봐야 할 예외는 트리 깊숙이 묻혀있었습니다.
public static class ExceptionExtensions
{
public static IEnumerable<T> innerExceptions<T>(this Exception ex)
where T : Exception
{
var rVal = new List<T>();
Action<Exception> lambda = null;
lambda = (x) =>
{
var xt = x as T;
if (xt != null)
rVal.Add(xt);
if (x.InnerException != null)
lambda(x.InnerException);
var ax = x as AggregateException;
if (ax != null)
{
foreach (var aix in ax.InnerExceptions)
lambda(aix);
}
};
lambda(ex);
return rVal;
}
}
사용법은 매우 간단합니다. 예를 들어, 우리가
catch (Exception ex)
{
var myExes = ex.innerExceptions<MyException>();
if (myExes.Any(x => x.Message.StartsWith("Encountered my specific error")))
{
// ...
}
}
Exception.GetBaseException()
?
재귀를 사용하여 어딘가의 유틸리티 클래스에 메서드를 만들 수 있습니다.
public Exception GetFirstException(Exception ex)
{
if(ex.InnerException == null) { return ex; } // end case
else { return GetFirstException(ex.InnerException); } // recurse
}
사용하다:
try
{
// some code here
}
catch (Exception ex)
{
Exception baseException = GetFirstException(ex);
}
제안 된 확장 방법 (좋은 아이디어 @dtb)
public static Exception GetFirstException(this Exception ex)
{
if(ex.InnerException == null) { return ex; } // end case
else { return GetFirstException(ex.InnerException); } // recurse
}
사용하다:
try
{
// some code here
}
catch (Exception ex)
{
Exception baseException = ex.GetFirstException();
}
public static Exception GetOriginalException(this Exception ex) { if (ex.InnerException == null) return ex; return ex.InnerException.GetOriginalException(); }
AggregateException.InnerExceptions
않습니까?
또 다른 방법은 GetBaseException()
두 번 호출하는 것입니다 .
Exception innermostException = e.GetBaseException().GetBaseException();
이면 AggregateException
첫 번째 호출이 가장 안쪽이 아닌 곳으로 AggregateException
이동하고 두 번째 호출이 해당 예외의 가장 안쪽 예외로 이동하기 때문에 작동합니다. 첫 번째 예외가 아닌 경우 AggregateException
두 번째 호출은 동일한 예외를 반환합니다.
LibraryException -> LibraryException -> LibraryException -> MyException
. 내 예외는 항상 체인의 마지막이며 자체 내부 예외가 없습니다.