我的问题表面上与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
同时使用Task
和Task<T>
,而无需编写方法的两个副本?
答案 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>
,但假设你的调用者不关心,它会保存一点重定向。