TPL 数据流块中抛出的 OperationCanceledException 被吞没

OperationCanceledException thrown in tpl dataflow block gets swallowed

出于某种原因,当 OperationCanceledException 被抛入 IDataflowBlock 时,该块不会将此异常传播到其 IDataflowBlock.Completion 任务。 运行 下面的代码示例 returns 出乎意料 IDataflowBlock.Completion.Status == TaskStatus.RanToCompletion

但是,如果块中抛出的异常类型更改为 ArgumentNullException,则 IDataflowBlock.Completion.Status 更改为 TaskStatus.Faulted 并且异常保存在其 InnerException 中属性。

知道为什么 OperationCanceledException 会被吞掉吗?

[TestFixture]
public class TplDataBlockExceptionTest
{
    [Test]
    public void ShouldThrowException()
    {
        // Arrange
        var block = new TransformBlock<int, string>(i =>
        {
            throw new OperationCanceledException();
            return i.ToString();
        });

        // Act

        block.Post(1);
        block.Complete();

        try
        {
            block.Completion.Wait();
        }
        catch (Exception)
        {
            // ignored
        }

        // Assert

        Assert.That(block.Completion.IsFaulted);
    }
}

我能够联系到 Microsoft 的 Stephen Toub,他能够确认此行为是设计使然:

https://github.com/dotnet/corefx/blob/master/src/System.Threading.Tasks.Dataflow/src/Blocks/TransformBlock.cs#L186-L190

https://github.com/dotnet/corefx/blob/master/src/System.Threading.Tasks.Dataflow/src/Internal/Common.cs#L152-L175