Какой смысл передавать ExceptionDispatchInfo вместо только Exception?
Я понимаю значение ExceptionDispatchInfo.Capture(e).Throw()
(сохраняет исходную трассировку стека), но каково преимущество использования Capture
раннем этапе и передача ExceptionDispatchInfo
по сравнению с просто пропусканием Exception
?
В качестве конкретного примера, сравнивая
static Exception CaptureException(Action action)
{
try
{
action();
return null;
}
catch (Exception e)
{
return e;
}
}
public void Test1()
{
ExceptionDispatchInfo.Capture(CaptureException(
() => throw new IOException("Test")))
.Throw();
}
с
static ExceptionDispatchInfo CaptureDispatchInfo(Action action)
{
try
{
action();
return null;
}
catch (Exception e)
{
return ExceptionDispatchInfo.Capture(e);
}
}
public void Test2()
{
CaptureDispatchInfo(() => throw new IOException("Test")).Throw();
}
оба дают по существу одинаковые трассировки стека (это похоже на async
изменение этого.). Таким образом, я действительно не понимаю, почему класс ExceptionDispatchInfo
существует вообще, а не только комбинированный метод ExceptionDispatchInfo.Capture(e).Throw()
.
Ответы
Ответ 1
ExceptionDispatchInfo используется для сохранения трассировки стека после создания исключения, что позволяет вам перехватить это исключение, не выбрасывая его немедленно (как часть перехвата), и вызвать такое исключение на более позднем этапе в будущем.
Я нашел хороший пример этого на https://thorarin.net/blog/post/2013/02/21/Preserving-Stack-Trace.aspx.
Ответ 2
Вы предполагаете, что исключения являются неизменными. Это не тот случай - исключение StackTrace изменяется при повторном вызове.
Целью ExceptionDispatchInfo.Capture
является захват потенциально мутирующего исключения StackTrace в определенный момент времени:
void Foo() => throw new InvalidOperationException ("foo");
Exception original = null;
ExceptionDispatchInfo dispatchInfo = null;
try
{
try
{
Foo();
}
catch (Exception ex)
{
original = ex;
dispatchInfo = ExceptionDispatchInfo.Capture (ex);
throw ex;
}
}
catch (Exception ex2)
{
// ex2 is the same object as ex. But with a mutated StackTrace.
Console.WriteLine (ex2 == original); // True
}
// So now "original" has lost the StackTrace containing "Foo":
Console.WriteLine (original.StackTrace.Contains ("Foo")); // False
// But dispatchInfo still has it:
try
{
dispatchInfo.Throw ();
}
catch (Exception ex)
{
Console.WriteLine (ex.StackTrace.Contains ("Foo")); // True
}