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

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

问题描述

我有一个异步方法返回一个任务。

我也想提供一个同步等价的,但我不希望它的消费者必须去拆包 AggregateException 秒。

现在我明白了,整个想法是,你不能随便挑一个在一般的方式,我知道我可以去阅读更多的负载斯​​蒂芬Toub的文章(我会的,但不是现在),我会理解所有并且可以决定自己。

在此期间,我想用我的任务其实只是链接工作流程没有并行的事实,只是中间的等待(不,不是TPL数据流),这不应该不会导致多个异常。在这种情况下,处理会是适当如下:

  CallAsync()等待()。
}
赶上(AggregateException AE)
{
    扔ae.Flatten()。第一个()

还是我保证一个 AggregateException 总是有一个的InnerException 即使有不止一个。或者是有,我应该回落到一个情况 .Flatten()。首先()


在一些TPL的文档,我看到 AggregateException 引用到展开()方法(如果不知道它是一个测试版的扩展或东西)。

作为一个占位符,我做的:

  void调用()
{
    尝试
    {
        CallAsync()等待()。
    }
    赶上(AggregateException前)
    {
        VAR翻译= ex.InnerException? 。ex.Flatten()InnerExceptions.First();
        如果(翻译== NULL)
            扔;
        扔翻译; }
}任务CallAsync(){...


解决方案

有没有干净的方式做到这一点,我知道的。不能使用抛someInnerException; ,因为你会失去堆栈无论异常起源于异步工作流程,如果你只是使用抛; 你显然会传播 AggregateException 。你会对同步方法做的是有某种包装例外,你可以东西了 AggregateException 的第一个异常到再抛,始终从同步版本的方法。

  void调用()
{
    尝试
    {
        CallAsync()等待()。
    }
    赶上(AggregateException前)
    {
        抛出新MyConsistentWrapperException(发生异常而执行我的工作流程检查内部异常的更多详细信息。ex.Flatten()InnerExceptions.First());
    }
}

FWIW,他们已经与<一个解决这4.5 href=\"http://msdn.microsoft.com/en-us/library/system.runtime.exceptionservices.exceptiondispatchinfo%28v=vs.110%29.aspx\">the新的 ExceptionDispatchInfo 类这将帮助你元帅跨线程异常不重击堆栈。然后,你可以写同步的版本是这样的:

  void调用()
{
    尝试
    {
        CallAsync()等待()。
    }
    赶上(AggregateException前)
    {
        。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();
    }
}

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

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