在非并行任务(翻译/展开聚合异常)方面实现同步方法的模式 [英] Pattern for implementing sync methods in terms of non-parallel Task (Translating/Unwrapping AggregateExceptions)

查看:180
本文介绍了在非并行任务(翻译/展开聚合异常)方面实现同步方法的模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Async方法返回一个任务。



我也希望提供一个同步的等效项,但我不希望它的消费者不得不拆包 AggregateException s。



现在我明白,整个想法是,你不能随意选择一个方式,我知道我可以去阅读载入更多的Stephen Toub文章(我会,但现在不是),我会理解这一切,并可以自己决定。



在此期间,我想使用这样一个事实:我的任务实际上只是链接工作流而不需要并行性,只是介入等待(不,不是TPL DataFlow),不应该导致多个异常。在这种情况下,如何处理如下:

  CallAsync()。Wait(); 
}
catch(AggregateException ae)
{
throw ae.Flatten()。First()

或者我保证一个 AggregateException 总是有一个 InnerException 甚至如果有不止一个。或者有一种情况我应该回到 .Flatten()。First()






在一些TPL文档中,我看到对 AggregateException Unwrap()方法的引用c>(不知道是扩展还是测试版中的某个东西)。



作为占位符,我在做:

  void Call()
{
try
{
CallAsync()。
}
catch(AggregateException ex)
{
var translations = ex.InnerException? 。ex.Flatten()InnerExceptions.First();
if(translated == null)
throw;
扔翻译; }
}

任务CallAsync(){...


解决方案

我知道没有这样做的干净的方式。您不能使用 throw someInnerException; ,因为在异步工作流中发生异常的任何地方都会丢失堆栈,如果您只是使用 throw; 你显然会传播 AggregateException 。对于同步方法你将要做的是有一些包装异常,你可以将 AggregateException 的第一个例外填入,然后从方法的同步版本。

  void Call()
{
try
{
CallAsync()。Wait();
}
catch(AggregateException ex)
{
抛出新的MyConsistentWrapperException(执行我的工作流时发生异常,检查内部异常的更多细节,ex.Flatten ).InnerExceptions.First());
}
}

FWIW,他们已经在4.5中解决了这个问题, a href =http://msdn.microsoft.com/en-us/library/system.runtime.exceptionservices.exceptiondispatchinfo%28v=vs.110%29.aspx =noreferrer>新的 ExceptionDispatchInfo class ,这将帮助您跨线程编排异常,而不需要打包堆栈。那么你可以写这样的同步版本:

  void Call()
{
try
{
CallAsync()。Wait();
}
catch(AggregateException ex)
{
ExceptionDispatchInfo.Capture(ex.Flatten()。InnerExceptions.First())。
}
}


I have an Async method returning a Task.

I also wish to offer a synchronous equivalent, but I don't want consumers of it to have to go unpacking AggregateExceptions.

Now I understand that the whole idea is that you couldn't arbitrarily pick one in a general way, and I know I could go read loads more Stephen Toub articles (I will, but not now) and I'll understand it all and can decide for myself.

In the interim, I want to use the fact that my tasks are actually just chained 'workflows' without parallelism, just intervening Waits (no, not TPL DataFlow) which shouldnt not result in more than one exception. In that case, would it be appropriate to handle as follows:

    CallAsync().Wait();
}
catch( AggregateException ae)
{
    throw ae.Flatten().First()

or am I guaranteed that an AggregateException always has an InnerException even if there are more than one. Or is there a case where I should fall back to .Flatten().First() ?


In some TPL docs, I see a reference to an Unwrap() method on AggregateException (not sure if it was an extension or something in a beta release).

As a placeholder, I'm doing:

void Call( )
{
    try
    {
        CallAsync().Wait();
    }
    catch ( AggregateException ex )
    {
        var translated = ex.InnerException ?? ex.Flatten().InnerExceptions.First();
        if ( translated == null )
            throw;
        throw translated;                 }
}

Task CallAsync(){ ...

解决方案

There's no "clean" way to do this that I know of. You can't use throw someInnerException; because you'll lose the stack wherever the exception originated in the the async workflow and if you just use throw; you're obviously going to propagate the AggregateException. What you would have to do for the synchronous method is have some kind of "wrapper" exception that you can stuff the first exception of the AggregateException into and then throw that consistently from the synchronous version of the method.

void Call()
{
    try
    {
        CallAsync().Wait();
    }
    catch (AggregateException ex)
    {
        throw new MyConsistentWrapperException("An exception occurred while executing my workflow. Check the inner exception for more details.", ex.Flatten().InnerExceptions.First());
    }
}

FWIW, they've solved this in 4.5 with the new ExceptionDispatchInfo class which will help you marshal exceptions across threads without whacking the stack. Then you could write the synchronous version like this:

void Call()
{
    try
    {
        CallAsync().Wait();
    }
    catch (AggregateException ex)
    {
        ExceptionDispatchInfo.Capture(ex.Flatten().InnerExceptions.First()).Throw();
    }
}

这篇关于在非并行任务(翻译/展开聚合异常)方面实现同步方法的模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆