如果我“async”/“await”,为什么编译器只允许通用返回任务?

Cer*_*rus 5 c# generics asynchronous async-await

我正在尝试从通用函数 ( ) 返回特定类型的值GenericGetter

当我尝试简单地返回Task来自 的键入结果时GenericGetter,编译器向我显示以下错误:

Cannot convert expression type 'System.Threading.Tasks.Task<Example.ChildClass>' 
    to return type 'System.Threading.Tasks.Task<Example.BaseClass>'
Run Code Online (Sandbox Code Playgroud)

GenericGetter但是,如果我创建包含call 的函数async,并且返回等待的值,则编译器不会介意。它可以编译,可以工作,但对我来说,添加的 async/await 似乎是多余的。

为什么GetChildClass不编译,而却GetChildClassAsync 编译

这是我的例子:

namespace Example
{
    public class BaseClass {}
    public class ChildClass : BaseClass {}

    public class MyExample
    {
        private async Task Main()
        {
            var foo = await GetChildClass().ConfigureAwait(false);
            var bar = await GetChildClassAsync().ConfigureAwait(false);
        }

        private Task<BaseClass> GetChildClass() =>
            GenericGetter<ChildClass>();

        private async Task<BaseClass> GetChildClassAsync() =>
            await GenericGetter<ChildClass>().ConfigureAwait(false);

        private Task<T> GenericGetter<T>()
            where T : BaseClass =>
            Task.FromResult<T>(null);
    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*eet 13

在 中GetChildClass,您试图将 a 转换Task<ChildClass>Task<BaseClass>- 这是行不通的,因为它Task<T>不变的(所有类也是如此;只有接口和委托通常可以是协变或逆变的 - 所有数组都支持协变,尽管以一种“有趣”的方式) 。

在 中GetChildClassAsync,您尝试将 a 转换ChildClass为 a BaseClass(这是正常继承和转换所允许的),然后 C# 编译器将其包装为 a Task<BaseClass>,所以这很好。

我明白为什么它看起来是多余的,并且可能Task<SomeBaseType>有更有效的方法可以完成它(如果能够使用框架方法/构造函数创建一个,那就太好了Task<SomeChildType>),但我建议只是忍受它。