简体   繁体   English

如何使异步方法通用于任务类型

[英]How to make async method generic over Task type

My question is on the surface very similar to Using a generic type as a return type of an async method . 我的问题表面上非常类似于使用泛型类型作为异步方法的返回类型 However, he did not have a real world usage scenario and so all that could be stated is that you can't do that. 但是,他没有现实世界的使用场景,所以可以说明的是你不能这样做。 I understand from Jon Skeet's answer to that question and from the blog post Why must async methods return Task? 我理解Jon Skeet对这个问题的回答 ,并从博客文章中了解为什么异步方法必须返回Task? why it is not supported. 为什么不支持。 The post discusses workarounds, but none of them apply to my use case. 该帖子讨论了解决方法,但它们都不适用于我的用例。

My question is, what is the best way to work around the language limitation given what I am trying to do? 我的问题是,考虑到我要做的事情,解决语言限制的最佳方法是什么?

In production code, we had a retry method that takes a Func<Task> and returns Task . 在生产代码中,我们有一个重试方法,它接受一个Func<Task>并返回Task We then needed to be able to retry TaskT> functions as well. 然后我们需要能够重试TaskT>函数。 So we changed the retry method to (slightly simplified): 所以我们将重试方法更改为(略微简化):

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

The compiler of course reports the error "The return type of an async method must be void, Task or Task". 编译器当然报告错误“异步方法的返回类型必须是无效的,任务或任务”。 Can I make Retry work with both Task and Task<T> without writing two copies of the method? 我是否可以使用TaskTask<T>进行Retry ,而无需编写方法的两个副本?

No, async just doesn't support that. 不,async只是不支持。 The simplest option to fake it would be: 伪造它的最简单的选择是:

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

That doesn't involve code duplication, but you do end up with an awful lot of layers of tasks on top of each other when you call the non-generic version. 这不涉及代码重复,但是当您调用非泛型版本时,最终会在彼此的顶层执行大量的任务层。 You could change the latter to: 您可以将后者更改为:

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

Then it will actually return a Task<int> , but assuming your callers don't care, it does save one bit of redirection. 然后它实际上将返回一个Task<int> ,但假设您的调用者不关心,它确实保存了一点重定向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM