使用任务并行库翻译无效任务的异常



我需要以与对正常同步代码执行以下操作相同的方式转换从Task<T>发出的异常:

try {
  client.Call();
} catch(FaultException ex) {
    if (ex.<Some check>)
        throw new Exception("translated");
}

但是,我想异步地执行此操作,即上面的Call实际上是Task CallAsync()

所以在C#5中,我的方法是这样的:

async Task CallAndTranslate()
{
    try{
        await client.CallAsync();
    } catch(FaultException ex) {
        if (ex.FaultCode ...)
            throw new Exception("translated");
    }
}

但我现在正在使用C#4。

那么,如果我想触发一个Task,但要翻译(TPL)Fault,然后再次将整个事件公开为Task<T>,我该怎么办呢?

  • 最初源于WCF Web服务,但这在这里并不重要

编辑:一种稍微具体一点的说法:

public class TranslatingExceptions
{
    public Task ApiAsync() // The inner layer exposes it exactly this way
    {
        return Task.Factory.StartNew(()=>{ throw new Exception( "Argument Null" );});
    }
    public Task WrapsApiAsync() // this layer needs to expose it exactly this way
    {
        // async preview pseudocode for what I need to do                            
        try {
            await ApiAsync(  );
        } catch (Exception exception){
            if( exception.Message == "Argument Null"  )
                throw new ArgumentNullException();
        }
    }
    [Fact]
    public void Works()
    {
        var exception = Record.Exception( () => 
            WrapsApiAsync().Wait());
        Assert.IsType<ArgumentNullException>( exception.InnerException);
    }
}

如果不需要C#5,您将如何实现WrapsApiAsync()

好的,现在我已经完全清楚你在寻找什么了,下面是你在4.0中构建等价物所需要做的一切:

public class TranslatingExceptions
{
    public Task ApiAsync() // The inner layer exposes it exactly this way
    {
        return Task.Factory.StartNew(()=>{ throw new Exception( "Argument Null" );});
    }
    public Task WrapsApiAsync() // this layer needs to expose it exactly this way
    {
        // Grab the task that performs the "original" work
        Task apiAsyncTask = ApiAsync();
        // Hook a continuation to that task that will do the exception "translation"
        Task result = aspiAsync.ContinueWith(antecedent =>
        {
            // Check if the antecedent faulted, if so check what the exception's message was
            if ( antecedent.IsFaulted 
              && antecedent.Exception.InnerException.Message == "Argument Null" )
            {
                throw new ArgumentNullException();
            }
        },
        TaskContinuationOptions.ExecuteSynchronously);
        // Now we return the continuation Task from the wrapper method so that the caller of the wrapper method waits on that
        return result;
    }
    [Fact]
    public void Works()
    {
        var exception = Record.Exception(() => 
                                         WrapsApiAsync().Wait());
        Assert.IsType<ArgumentNullException>(exception.InnerException);
    }
}

这应该能完成你想要的。需要注意的一点是,我在创建延续时使用TaskContinuationOptions.ExecuteSynchronously。这是因为这项工作又小又紧,而且您不想为了进行此检查而等待整个其他线程从线程池中被调度程序提取。

相关内容

最新更新