使用任务并行库 a la wait 转换 void 任务的异常

发布于 2024-12-26 10:46:21 字数 1628 浏览 6 评论 0原文

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

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

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

因此,在 C# 5 中,我的方法将如下所示:

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

但我现在使用 C# 4。

那么,如果我想触发一个任务,但要转换 (TPL) 故障,然后再次将整个事件作为 Task 公开,我该怎么办?

  • 最初源自 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()

I need to translate an exception emanating from a Task<T> in the same manner that doing the following would for normal synchronous code:

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

However, I want to do this asynchronously, i.e., Call above is actually Task CallAsync().

So in C# 5 my method would look like this:

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

But I'm using C# 4 for now.

So what can I do given that I want to trigger a Task but have the (TPL) Fault be translated and then expose the whole thing once again as a Task<T>?

  • originally emanating from a WCF webservice but that's not important here

EDIT: A slightly more concrete way of saying it:

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);
    }
}

How would you implement WrapsApiAsync() without needing C# 5?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

卷耳 2025-01-02 10:46:21

好的,现在我完全清楚您在寻找什么,这就是您在 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。这是因为这项工作很小而且很紧张,您不希望因为等待调度程序从线程池中取出整个其他线程来执行此检查而产生开销。

Ok, so now that I'm entirely clear on what you're looking for, here's all you would need to do to build the equivalent in 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);
    }
}

This should accomplish what you're looking for. One thing to note is that I use TaskContinuationOptions.ExecuteSynchronously when creating the continuation. This is because this work is small and tight and you don't want to incur the over head of waiting for a whole other thread having to be picked up from the thread pool by the scheduler just to do this check.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文