将IEnumerable<T>转换为List<T>。

4

好的,我已经四处寻找答案,但是找不到。我有一个返回值为的方法。


请提供更多上下文以便更准确地翻译。
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()方法吗? - Blair Scott
1
请不要在标题前加上"C#"。这就是标签的作用。 - John Saunders
6个回答

10

并非所有的 IEnumerable<T> 都是 List<T>,反之亦然。

你可以尝试将其强制转换为 List<T>,但这是不好的做法,如果实际上不是列表,则可能会失败。相反,你可以从枚举中创建一个新的列表。

new List<T>(yourEnumerable);

或者使用 Linq

yourEnumerable.ToList();

嗯,不要强制转换为 List<T>,这可能会在未来引起问题。只需使用上述两种方法之一即可。 - Joe Flateau
是的,因此我说它可能会失败。如果您真的想要一个List<T>,最好从枚举中创建一个新列表。 - aqwert
@aqwert 我确实尝试了新的List<T>(yourEnumerable); 这个方法,它可以正常工作。我只是想知道为什么不能从IEnumerable<T>转换到List<T>,这似乎是可以做到的。 - Cam
你可以通过强制类型转换来实现。但是,有许多类(例如ObservableCollection<T>)也实现了IEnumerable<T>,因此强制转换并不是一个好的选择。编译器不知道你想要哪个,所以你需要明确表达,确保你知道自己想要什么,避免犯任何愚蠢的错误。你可以从List<T>转换为IEnumerable<T>,因为它知道这样做没有歧义。 - aqwert
@aqwert 这一行对我来说已经说明了一切 并非所有的IEnumerable<T>都是List<T>,反之亦然。这就是为什么我必须从枚举中创建一个新列表。感谢大家的帮助。 - Cam

3

List<ICar> 实现了 IEnumerable<ICar> - 你是对的。但这意味着你可以隐式地将 List<ICar> 转换为 IEnumerable<ICar> - 而不能反过来转换。解决你的问题,只需在 IEnumerable 上调用 ToList() 将其转换为 List


1

您可以调用 ToList 将您的 IEnumerable<Car> 转换为 List<Car>

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

这不会自动发生,因为虽然您可以尝试将 IEnumerable<Car> 向下转换为 List<Car>

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

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


1
一个 IEnumerable<T> 可以是一个 List<T>,但不一定是。您可以使用 LINQ 的 IEnumerable<T>.ToList<T>() 将任何 IEnumerable<T> 转换为 List<T>
IEnumerable<T> foo = ThatMethodYouWereTalkingAbout();
List<T> bar;
if (foo is List<T>)
    bar = (List<T>)foo;
} else {
    bar = new List<T>(foo);
}

0

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

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

所有的IEnumerable承诺给你的只是可以获取下一个元素。而List承诺的更多:例如通过索引访问和它有一个有限的长度。

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

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

你想调用ToList来获取一个列表。请注意,这可能不会在像上面那样的情况下终止。


0

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

在语言规范中,List<ICar>IEnumerable<ICar>之间不具备赋值兼容性。但是,反过来是成立的。 IEnumerable<ICar>可以赋值给List<ICar>

如果你将赋值兼容性视为一种关系,那么这就更有意义了。如果x <= y成立,则x >= y不成立(除非y = x)。 (具体而言,2 < 3 = true,因此2 > 3不成立。)

在您的情况下,我们可以将汽车列表的值分配给类型为IEnumerable<ICar>的变量。

如果我们可以表示关系为

List<ICar> <= IEnumerable<ICar> = true。

那么它就遵循

List<ICar> >= IEnumerable<ICar> = false

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


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