【问题标题】:IEnumerable<T> to List<T>IEnumerable<T> 到 List<T>
【发布时间】:2012-05-02 11:08:20
【问题描述】:

好的,我环顾四周,找不到答案。我有一个返回

的方法
IEnumerable<ICar> 

并且调用方法将方法的结果存储在

List<ICar> 

但我收到以下错误。

System.Collections.Generic.IEnumerable<Test.Interfaces.ICar> to 
System.Collections.Generic.List<Test.Interfaces.ICar>. An explicit conversion exists   
(are you missing a cast?)   

我在msdn上看了

IEnumerable<T> interface and List<T> class. 

以下行来自 msdn。

public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection,   
IEnumerable

我只是不明白为什么我不能分配

IEnumerable<ICar> to List<ICar>. 

谁能给我解释一下。我错过了什么。

【问题讨论】:

  • 你试过在返回的对象上调用 ToList() 吗?
  • 请不要在标题前加上“C#”。这就是标签的用途。

标签: c# c#-4.0


【解决方案1】:

并非所有IEnumerable&lt;T&gt; 都是List&lt;T&gt;。反之亦然。

您可以尝试强制转换为 List&lt;T&gt;,这是一种不好的做法,如果它确实不是一个列表,则可能会失败,或者您可以从枚举中创建一个新列表

new List<T>(yourEnumerable);

或使用 Linq

yourEnumerable.ToList();

【讨论】:

  • 呃,不要投到List&lt;T&gt;,以后可能会出问题。只需使用上述两种方法之一即可。
  • 是的.. 因此我说它可能会失败。如果你真的想要一个 List,最好的做法是从枚举中创建一个新列表
  • @aqwert 我确实尝试过 new List(yourEnumerable);这很有效,我只是想了解为什么我不能从 IEnumerable 转到 List 似乎可以这样做。
  • 你可以通过演员表。但是有许多类,例如 ObservableCollection 也实现了 IEnumerable 所以强制转换不是一件好事。编译器不知道你想要哪一个,所以你要明确以确保你知道你想要什么并且不会犯任何愚蠢的错误。您可以从 List 转到 IEnumerable 因为它知道这样可以毫无歧义地工作。
  • @aqwert 这行说明了一切并非所有 IEnumerable 都是 List。反之亦然。这就是为什么我必须从枚举中创建一个新列表。感谢大家的帮助。
【解决方案2】:

List&lt;ICar&gt; 实现 IEnumerable&lt;ICar&gt; - 你是对的。但这意味着您可以将 List&lt;ICar&gt; 隐式转换为 IEnumerable&lt;ICar&gt; - not 反过来。要解决您的问题,只需在IEnumerable 上调用ToList() 将其转换为List

【讨论】:

    【解决方案3】:

    IEnumerable&lt;T&gt; 可以是 List&lt;T&gt;,但不一定是一个。您可以使用 LINQ 的 IEnumerable&lt;T&gt;.ToList&lt;T&gt;() 将任何 IEnumerable&lt;T&gt; 转换为 List&lt;T&gt;

    IEnumerable<T> foo = ThatMethodYouWereTalkingAbout();
    List<T> bar;
    if (foo is List<T>)
        bar = (List<T>)foo;
    } else {
        bar = new List<T>(foo);
    }
    

    【讨论】:

      【解决方案4】:

      您可以致电ToList 将您的IEnumerable&lt;Car&gt; 转换为List&lt;Car&gt;

      IEnumerable<ICar> cars = ...;
      List<ICar> list = cars.ToList(); // OK
      

      这不会自动发生,因为尽管您可以尝试将 IEnumerable&lt;Car&gt; 向下转换为 List&lt;Car&gt;

      IEnumerable<ICar> cars = ...;
      List<ICar> list = (List<ICar>)cars; // Compiles, but could fail at runtime.
      

      没有implicit 转换运算符,因此C# 编译器不允许在没有强制转换的情况下进行赋值。向下转换可能会在运行时失败,因此在大多数情况下最好使用ToList

      【讨论】:

        【解决方案5】:

        所有列表都是 IEnumerable,但所有 Innumerable 都不是列表。根据MSDNIEnumerable

        公开枚举器,它支持对非泛型集合的简单迭代。

        所有 IEnumerable 都向您承诺您可以获得下一个元素。 List 承诺更多:例如按索引访问,并将其作为有限长度。

        IEnumerable 不是这种情况。例如下面的代码实际上并没有创建一个列表,事实上,你不能从中创建一个列表。每次你要求一个新元素时,它都会给你一个。但它只在被问到时才计算它。 :

        IEnumerable<int> Numbers() {
            int i=0;
            while(true) {
                yield return unchecked(i++);
            }
        }
        

        您想致电ToList 获取列表。请注意,这可能会在上述情况下终止。

        【讨论】:

          【解决方案6】:

          我们不能通过变量赋值将派生程度较低的类型分配给派生程度较高的类型。那不是类型安全的。

          在语言规范中。说话,List&lt;ICar&gt;IEnumerable&lt;ICar&gt; 的分配不兼容。但是,反之亦然。 IEnumerable&lt;ICar&gt; 的赋值与 List&lt;ICar&gt; 兼容。

          如果您将分配兼容性可视化为关系,则更有意义。如果 x = y 不为真(除非 y = x)。 (具体来说,2 3 不正确。)

          在您的情况下,我们可以将汽车列表的值分配给IEnumerable&lt;ICar&gt; 类型的变量。

          如果我们可以将关系表示为

          List&lt;ICar&gt; IEnumerable<ICar> = 真。

          那么接下来就是

          List&lt;ICar&gt; >= IEnumerable&lt;ICar&gt; = 假

          这是错误的,因为我们知道的第一个关系是正确的。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-02-24
            • 2014-01-19
            • 2021-12-02
            • 2015-11-19
            • 1970-01-01
            相关资源
            最近更新 更多