【问题标题】:Why Does it Not Compile?为什么它不编译?
【发布时间】:2020-12-16 08:41:29
【问题描述】:

我有这个代码:

static List<string> lst = new List<string>();

public static Task<IEnumerable<String>> GetStrings() {
    IEnumerable<String> x = lst;
    
    // This line below compiles just fine.
    // return Task.Run(() => x);
    
    // This line gives a compiler error:
    // Cannot implicitly convert type 'System.Threading.Tasks.Task<System.Collections.Generic.List<string>>' to
    // 'System.Threading.Tasks.Task<System.Collections.Generic.IEnumerable<string>>'
    return Task.Run(() => lst);
}    

为什么这行编译得很好:return Task.Run(() =&gt; x);return Task.Run(() =&gt; lst); 给出编译器错误:

不能隐式转换类型 'System.Threading.Tasks.Task' 到 'System.Threading.Tasks.Task'

我认为既然List&lt;string&gt;IEnumerable&lt;string&gt;,我不应该显式设置x。我的意思是,编译器知道lstIEnumerable&lt;string&gt;

我想我一定遗漏了一些基本的东西。

【问题讨论】:

  • 你可以用Task.Run(() =&gt; (IEnumerable&lt;String&gt;)lst);修复它
  • 错误是关于 Task&lt;T&gt; 类型,而不是 List 和 IEnumerable。仅仅因为类型参数具有继承关系并不意味着泛型类型也具有这种关系
  • Task&lt;TResult&gt; 不是covariant
  • Task&lt;T&gt; 没有将 T 声明为 out TIEnumerable 声明

标签: c#


【解决方案1】:

因为 C# 首先 尝试确定您的表达式 Task.Run(() =&gt; lst) 的类型,然后 然后 检查它是否适合您的方法。

  1. lstList&lt;string&gt;
  2. 因此,() =&gt; lst 是一个 lambda,其返回值为 List&lt;string&gt;
  3. 因此,Task.Run&lt;TResult&gt;(Func&lt;TResult&gt;) 调用时使用 () =&gt; lst 推断 List&lt;string&gt; 作为其类型参数 TResult
  4. 因此,Task.Run(() =&gt; lst) 的类型为 Task&lt;List&lt;string&gt;&gt;

然后您尝试使用Task&lt;List&lt;string&gt;&gt; 类型的值作为返回Task&lt;IEnumerable&lt;string&gt;&gt; 的方法的返回值。 Task&lt;TResult&gt; 不是协变的,因此会出现编译时错误。

(顺便说一句:有一个协变的ITask&lt;out TResult&gt; 接口可以解决这个问题,但是the .NET development team decided against it。)

是的,编译器可以检查您是如何使用在步骤 4 中创建的表达式并尝试lst 的不同接口以使其适合,但这是一个功能C#(目前)没有的(在我个人看来,由于成本效益比低,可能不值得实施和维护)。


要解决这个问题,您可以在第 2 步中通过显式转换返回类型来提供不同的类型:

return Task.Run(() => (IEnumerable<string>)lst);

或通过显式声明 lambda 表达式的类型:

return Task.Run(new Func<IEnumerable<string>>(() => lst));

或者您可以使用显式类型参数覆盖第 3 步中的自动推理:

return Task.Run<IEnumerable<string>>(() => lst);

【讨论】:

  • C# 似乎正在逐渐向目标类型表达式的使用分析方向发展。
【解决方案2】:

问题是您在这里使用了不同的数据类型(List&lt;T&gt;IEnumerable&lt;T&gt;)。您可以使用类型转换来解决此问题,例如:

Task.Run(() =&gt; (IEnumerable&lt;string&gt;)lst);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-21
    • 1970-01-01
    • 2010-12-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多