2014-03-19 27 views
2

我使用TPL Dataflow库中的TransformBlock,并且我意识到,在转换过程中抛出异常时,我会在“Receive”方法中得到一个通用异常,但是没有提及原来的一个。使用TransformBlock捕获原始异常

在此代码:

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: 

没有提及到原来的异常类型或它的消息。有没有办法强制它扔原来的?或者至少,用它作为内部异常?

回答

4

您看到一个来自ReceiveAsync的例外。 InvalidOperationException是预期的行为。

如果要检测或响应块故障,然后awaitIDataflowBlock.Completion属性。

+0

但是,如果变换永远不会结束呢?或者如果只有一些项目失败? – vtortola

+0

如果任何项目的转换失败,块故障并且不会接受任何附加项目。如果转换永远不会结束,那么这就是一个bug - 就像一个永不停息的while循环一样。 –

+0

我想表示这是一个持续的转换,因为新项目到达并且转换不应该停止,因为其中一个失败。但我明白了。 – vtortola

0

我只是为了完成而添加此响应。 As @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 
}