Catching AggregateException

后端 未结 2 2087
情书的邮戳
情书的邮戳 2021-02-03 22:27

I am trying to throw and catch an AggregateException. I did not use exceptions very much on C#, but the behaviour I found is a little bit surprising.

My code is:

2条回答
  •  南旧
    南旧 (楼主)
    2021-02-03 23:12

    I agree with others: this is a bug in .Net and you should report it.

    The cause is in the method QueryEnd() in the internal class QueryTaskGroupState. Its decompiled (and slightly modified for clarity) code looks like this:

    try
    {
      this.m_rootTask.Wait();
    }
    catch (AggregateException ex)
    {
      AggregateException aggregateException = ex.Flatten();
      bool cacellation = true;
      for (int i = 0; i < aggregateException.InnerExceptions.Count; ++i)
      {
        var canceledException =
            aggregateException.InnerExceptions[i] as OperationCanceledException;
        if (IsCancellation(canceledException))
        {
          cacellation = false;
          break;
        }
      }
      if (!cacellation)
        throw aggregateException;
    }
    finally
    {
      this.m_rootTask.Dispose();
    }
    if (!this.m_cancellationState.MergedCancellationToken.IsCancellationRequested)
      return;
    if (!this.m_cancellationState.TopLevelDisposedFlag.Value)
      CancellationState.ThrowWithStandardMessageIfCanceled(
        this.m_cancellationState.ExternalCancellationToken);
    if (!userInitiatedDispose)
      throw new ObjectDisposedException(
        "enumerator", "The query enumerator has been disposed.");
    

    Basically, what this does is:

    • rethrow the flattened AggregateException if it contains any non-cancellation exceptions
    • throw new cancellation exception if cancellation was requested (or return without throwing, I don't really understand that part, but I don't think it's relevant here)
    • else throw ObjectDisposedException for some reason (assuming userInitiatedDispose is false, which it is)

    So, if you throw an AggregateException with no inner exceptions, ex will be an AggregateException containing your empty AggregateExcaption. Calling Flatten() will turn that into just an empty AggreateException, which means it doesn't contain any non-cancellation exception, so the first part of the code thinks this is cancellation and doesn't throw.

    But the second part of the code realizes this isn't cancellation, so it throws a completely bogus exception.

提交回复
热议问题