我了解ExceptionDispatchInfo.Capture(e).Throw()的值(value)(保留了原始的堆栈跟踪),但是,尽早使用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()方法。

最佳答案

您假设异常是不可变的。事实并非如此-异常的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
}

10-07 18:12