为什么异步方法的返回类型不能派生自Task?

4

我有一个类(简化示例,仅显示相关部分)

public class AsyncScenario : Task<Scenario>
{
    public async AsyncScenario Test(Func<Task> action)
    {
        return await this;           
    }
}

我无法编译这个代码,因为该方法的返回类型为:

编译器错误 CS1983: “异步方法的返回类型必须是 void、Task 或 Task<T>”

为什么异步方法不允许返回从 Task<T> 派生的类?


1
编译器应该如何实例化您的 DerivedTask<T>?但在这种情况下,没有理由使用 async。您可以删除 awaitasync,它仍然可以正常工作。 - Aron
2个回答

7
因为C#规范是这么说的?除了Eric Lippert或其他语言设计团队成员发表意见,你不会得到比这更好的答案。其他任何东西都将是纯粹的猜测和观点。
话虽如此,在async方法中,返回值由return语句隐含表示,那么在这种情况下,你认为规范应该是什么样子呢?显然,await this解析为Scenario对象... C#编译器应该如何从该表达式类型合成一个新的AsyncScenario对象呢?
我想,你可能会想出一些额外的规则,可以在规范中明确提供某些机制。但在我看来,这些规则将比现有规范要复杂得多,其中返回类型始终是已知于规范作者并具有清晰的规则以在方法首次返回时创建并且同样重要的是,在执行return语句时改变状态的类型。
我认为规则存在的方式很可能是因为要做出改变需要大量的努力,并且会极大地增加编译器的复杂性和出错的可能性。
顺便说一下,通过一些搜索可以找到有价值的信息:为什么异步方法必须返回Task?,作者是VB.NET的语言设计师Lucian Wischik(但该文章同样适用于C#)。还可以参考Jon Skeet在将泛型类型用作异步方法的返回类型中的回答。

1
正在考虑“任意任务式返回类型”(Arbitrary task-like return types)。可能不会很快出现,但未来有可能实现。 - Stephen Cleary
2
@StephenCleary:昨天我和Lucian一起吃午餐,他告诉我他仍在积极追求这个功能,所以很有可能会实现。当然,不能保证。 - Eric Lippert

1

您可以等待任何返回带有GetAwaiter方法的类型的方法:

    public static async Task<Scenario> Test()
    {
        return await new AsyncScenario();
    }

    public class AsyncScenario
    {
        public TaskAwaiter<Scenario> GetAwaiter()
        {
            return new TaskAwaiter<Scenario>();
        }
    }

你的 Test() 方法返回的是 Task<string> 而不是 AsyncScenario。那么,你的回答如何解释该方法的 返回类型 不能为 AsyncScenario 呢? - Peter Duniho

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接