如何在任务类型

时间:2015-12-01 19:05:26

标签: c# generics asynchronous

我的问题表面上与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”。我是否可以Retry同时使用TaskTask<T>,而无需编写方法的两个副本?

1 个答案:

答案 0 :(得分:5)

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

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<int>,但假设你的调用者不关心,它会保存一点重定向。