使用泛型类型作为异步方法的返回类型

Posted

技术标签:

【中文标题】使用泛型类型作为异步方法的返回类型【英文标题】:Using a generic type as a return type of an async method 【发布时间】:2014-05-29 17:32:14 【问题描述】:

上一个问题让我想知道为什么下面的方法会引发编译时错误:

async 方法的返回类型必须为 void、Task 或 Task

public async T MyMethodAsync<T>() where T : Task

     // Irrelevant code here which returns a Task

既然我们在编译时知道 T 始终是 Task 或派生类型,为什么这不起作用?

编辑

我问的原因是方法可能返回TaskTask&lt;T&gt;。假设该方法可以返回任何一个并且我不想重复代码。

当然,这都是理论上的,并非用于生产目的。

编辑 2

找到了 Lucian Wischik 的一篇很棒的文章: Why must async return Task

【问题讨论】:

你的意思是让它成为一个通用方法吗? 您是否错过了函数的通用定义?应该是MyMethodAsync&lt;T&gt;()。您还返回T 还是Task?如果您返回后者,您只需将返回类型设为Task 我不确定编译器是否有理由拒绝这一点,但退后一步我不得不想知道为什么带有where T : AnySpecificType 的泛型首先需要是泛型的。 例如返回类型可能是Task&lt;T&gt; @YuvalItzchakov:请尝试编写一个对T=TaskT=Task&lt;string&gt; 都有效的方法体。 【参考方案1】:

三个问题:

仅仅因为T 是“Task 或派生类型”并不意味着它是TaskTask&lt;T&gt;。如果我调用MyMethodAsync&lt;MyCustomTask&gt;,其中MyCustomTask 源自Task,你会期待什么?

编译器在编译方法时需要知道它是在构建返回 Task 还是 Task&lt;T&gt; 的状态机 - 它在不同的情况下使用不同的辅助类

如果异步方法的返回类型为Task,则任何return 语句都不能指定值;如果它的返回类型为Task&lt;T&gt;,则任何return 语句都必须指定一个可隐式转换为T 的值。这怎么能在MyMethodAsync 中工作?这有点像说“我的方法要么是void,要么返回T——你可以决定何时调用它”。

目前尚不清楚您要在这里实现什么,但基本上这是行不通的。

【讨论】:

我明白了。所以基本上这与编译器需要知道是否没有返回值(如果它是Task)或是否有(Task&lt;T&gt;)有关。至于MyCustomTaskTask的派生类型是否可以作为async方法的返回类型? @YuvalItzchakov:不,不是——但它满足你的泛型类型参数约束。 请问为什么?或者那会是一个不同的问题? @YuvalItzchakov:为什么?为什么它不是有效的返回类型?您如何期望编译器知道如何构造一个?请记住,编译器会将异步方法转换为状态机,并在必要时计算出如何返回TaskTask&lt;T&gt;。它通过特定于TaskTask&lt;T&gt; 的帮助类来实现。 好吧,现在我明白了。我不知道推断未知派生任务类型的问题。我应该探索这些帮助类以准确了解发生了什么。【参考方案2】:

我想不出MyMethodAsync 的有效定义,它允许它返回一个从Task 派生的通用T,而无需在编译时知道该类型是什么或采用某种参数。

如果您真的返回 TaskTask&lt;T&gt;,那么您可以更新您的签名以反映这一事实并避免问题。

如果您确实需要从Task 派生的某种类型,那么您将需要重写您的逻辑以返回TaskTask&lt;T&gt; 并环绕该其他类型。假设这是不可接受的,您将需要删除 async 并自己处理状态机。

【讨论】:

以上是关于使用泛型类型作为异步方法的返回类型的主要内容,如果未能解决你的问题,请参考以下文章

使用泛型类型作为异步方法的返回类型

201671010113 2016-2017-2 《JAVA程序设计》第十周

java 方法中如何在返回类型使用泛型

TS泛型类、泛型接口、泛型函数

Java泛型

java 16 -7 泛型方法和泛型接口(泛型类相似)