使用TransformBlock捕获原始异常

时间:2014-03-19 14:10:40

标签: .net task-parallel-library task async-await tpl-dataflow

我正在使用TPL Dataflow库中的TransformBlock,我意识到在转换过程中抛出异常时,我会在" Receive"中得到一个通用异常。方法,但没有提到原来的。

在此代码中:

Func<Int32, Task<String>> transformer = async i => { await Task.Yield(); throw new ArgumentException("whatever error"); };
TransformBlock<Int32, String> transform = new TransformBlock<int, string>(transformer);
transform.Post(1);

try
{
    var x = await transform.ReceiveAsync();
}
catch (Exception ex)
{
    // catch
}

例外ex包含:

System.InvalidOperationException was caught
  HResult=-2146233079
  Message=The source completed without providing data to receive.
  Source=System.Threading.Tasks.Dataflow
  StackTrace:
       at System.Threading.Tasks.Dataflow.Internal.Common.InitializeStackTrace(Exception exception)
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       at DoubleQueueTest.Program.<testwhatever>d__5.MoveNext() in c:\Users\vtortola\Documents\Visual Studio 2013\Projects\DoubleQueueTest\DoubleQueueTest\Program.cs:line 43
  InnerException: 

不提及原始异常类型或其消息。有没有办法强迫它抛出原来的?或者至少使用它作为内部例外?

2 个答案:

答案 0 :(得分:5)

您正在查看ReceiveAsync的例外情况。 InvalidOperationException是预期的行为。

如果要检测或响应阻止故障,请await IDataflowBlock.Completion属性。

答案 1 :(得分:0)

我正在添加此响应仅用于完成。正如@Stephen清楚地指出的那样,如果其中一个项目出现故障,转换将会出错。因此,如果您的转换因单个项目出错而无法停止,我使用了这种方法:

创建一个代表操作结果的小类:

 class TransformResult<T>
 {
     public T Result { get; set; }
     public ExceptionDispatchInfo Error { get; set; }
 }

如果有异常,请捕获并返回结果:

Func<Int32, Task<TransformResult<String>>> transformer = async i => 
{ 
    await Task.Yield();
    try
    {
        // do whatever

        throw new ArgumentException("whatever error");
    }
    catch (Exception ex)
    {
        return new TransformResult<String>() { Error = ExceptionDispatchInfo.Capture(ex) };
    }
};

等待转换结果时,如果结果包含错误...抛出它:

var transform = new TransformBlock<int, TransformResult<String>>(transformer);
transform.Post(1);

try
{
    var x = await transform.ReceiveAsync();
    if (x.Error != null)
        x.Error.Throw();
}
catch (Exception ex)
{
    // catch
}