【问题标题】:How to make async method generic over Task type如何使异步方法在任务类型上通用
【发布时间】:2015-12-01 19:05:26
【问题描述】:

我的问题表面上与Using a generic type as a return type of an async method 非常相似。然而,他没有真实世界的使用场景,所以只能说你不能那样做。我从Jon Skeet's answer 到该问题以及从博客文章Why must async methods return Task? 了解为什么不支持它。该帖子讨论了解决方法,但没有一个适用于我的用例。

我的问题是,鉴于我正在尝试做的事情,解决语言限制的最佳方法是什么?

在生产代码中,我们有一个重试方法,它接受 Func<Task> 并返回 Task。然后我们还需要能够重试TaskT> 函数。于是我们把重试方式改成了(稍微简化了):

public static async T Retry<T>(Func<T> action) where T : Task
{
    for (var i = 0; ; i++)
    {
        try
        {
            return await action();
        }
        catch (Exception)
        {
            if (i >= 3)
                throw;
        }       
    }
}

编译器当然会报错“异步方法的返回类型必须是void,Task或Task”。我可以让RetryTaskTask&lt;T&gt; 一起工作,而无需编写该方法的两个副本吗?

【问题讨论】:

    标签: c# generics asynchronous


    【解决方案1】:

    不,异步只是不支持。伪造它的最简单选择是:

    public static async Task<T> Retry<T>(Func<Task<T>> action)
    {
        for (var i = 0; ; i++)
        {
            try
            {
                return await action();
            }
            catch (Exception)
            {
                if (i >= 3)
                    throw;
            }       
        }
    }
    
    public static async Task Retry(Func<Task> action)
    {
        Func<Task<int>> d = async () => { await action(); return 0; };
        await Retry(d);
    }
    

    这不涉及代码重复,但是当您调用非通用版本时,您确实会得到很多层层叠叠的任务。您可以将后者更改为:

    public static Task Retry(Func<Task> action)
    {
        Func<Task<int>> d = async () => { await action(); return 0; };
        return Retry(d);
    }
    

    然后它会实际上返回一个Task&lt;int&gt;,但假设你的调用者不在乎,它确实节省了一点重定向。

    【讨论】:

      猜你喜欢
      • 2019-11-25
      • 1970-01-01
      • 1970-01-01
      • 2021-10-01
      • 1970-01-01
      • 2018-04-08
      • 1970-01-01
      • 1970-01-01
      • 2015-03-08
      相关资源
      最近更新 更多