C# IEnumerable 和 Array、IList 和 List 有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/764748/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the difference between IEnumerable and Array, IList and List?
提问by chat
What's the difference between IEnumerableand Array?
IEnumerable和 和有Array什么区别?
What's the difference between IListand List?
IList和 和有List什么区别?
These seem to have the same function.
这些似乎具有相同的功能。
采纳答案by itowlson
IEnumerable provides only minimal "iterable" functionality. You can traverse the sequence, but that's about it. This has disadvantages -- for example, it is very inefficient to count elements using IEnumerable, or to get the nth element -- but it has advantages too -- for example, an IEnumerable could be an endless sequence, like the sequence of primes.
IEnumerable 仅提供最小的“可迭代”功能。您可以遍历序列,但仅此而已。这有缺点——例如,使用 IEnumerable 计算元素或获取第 n 个元素的效率非常低——但它也有优点——例如,IEnumerable 可能是一个无限序列,如素数序列。
Array is a fixed-size collection with random access (i.e. you can index into it).
Array 是一个固定大小的集合,可以随机访问(即您可以对其进行索引)。
List is a variable-size collection (i.e. you can add and remove elements) with random access.
List 是一个可变大小的集合(即您可以添加和删除元素),可以随机访问。
IList is an interface which abstracts list functionality (count, add, remove, indexer access) away from the various concrete classes such as List, BindingList, ObservableCollection, etc.
IList 是一个接口,它将列表功能(计数、添加、删除、索引器访问)从各种具体类(如 List、BindingList、ObservableCollection 等)中抽象出来。
回答by jfclavette
IEnumerable and IList are interfaces. Array and List are classes. Array implements IEnumerable. List implements IList which extends IEnumerable.
IEnumerable 和 IList 是接口。Array 和 List 是类。数组实现 IEnumerable。List 实现了扩展 IEnumerable 的 IList。
Edit: as itowlson mentionned in a comment, Array also implements IList.
编辑:正如 itowlson 在评论中提到的,Array 也实现了 IList。
回答by Mark Simpson
IEnumerable is an interface that allows the iteration through a collection of items (e.g. via the foreach keyword).
IEnumerable 是一个允许迭代项目集合的接口(例如,通过 foreach 关键字)。
An array is a .NET intrinsic. It holds items of the same type, but it is of a fixed size. Once you create an array with x elements, it cannot grow or shrink.
数组是 .NET 内在函数。它包含相同类型的项目,但具有固定大小。一旦你创建了一个包含 x 个元素的数组,它就不能增长或缩小。
IList defines the interface for a list, and also implements IEnumerable.
IList 定义了列表的接口,并且还实现了 IEnumerable。
List implements the IList interface; it is a concrete type of list.
List 实现了 IList 接口;它是一种具体的列表类型。
The difference between .NET Lists and arrays is that lists can have elements added to them -- they grow to be big enough to hold all of the required items. The list stores this internally in an array and, when the array is no longer big enough to hold all of the elements, a new array is created and the items copied across.
.NET 列表和数组之间的区别在于列表可以添加元素——它们会增长到足以容纳所有需要的项目。该列表将其内部存储在一个数组中,当数组不再足够容纳所有元素时,将创建一个新数组并复制项目。
IList & arrays both implement IEnumerable. That's how interfaces work -- classes implement the contract and behave in a similar fashion and can be treated similarly as a result (you know that the class implements IEnumerable, you don't need to know the hows or the whys). I suggest you read up on interfaces and so forth.
IList 和数组都实现了 IEnumerable。这就是接口的工作方式——类实现契约并以类似的方式运行,因此可以类似地对待(你知道类实现了 IEnumerable,你不需要知道如何或为什么)。我建议你阅读接口等。
回答by Dmitri Nesteruk
IEnumerableis a general-purpose interface that is used by many classes, such as Array, Listand Stringin order to let someone iterate over a collection. Basically, it's what drives the foreachstatement.
IEnumerable是一个被许多类使用的通用接口,例如Array,List并且String为了让某人迭代一个集合。基本上,这就是驱动foreach声明的原因。
IListis typically how you expose variables of type Listto end users. This interface permits random access to the underlying collection.
IList通常是您List向最终用户公开类型变量的方式。该接口允许随机访问底层集合。
回答by row1
Generation of an IEnumerable collection is lazy. Example:
IEnumerable 集合的生成是惰性的。例子:
public IEnumerable<int> GetTwoInts()
{
yield return 1;
yield return 2;
}
public void Something()
{
var twoInts = GetTwoInts();
}
In the method Something the call to GetTwoInts() will not actually result in the method GetTwoInts being executed since the enumeration is never iterated over.
在 Some 方法中,对 GetTwoInts() 的调用实际上不会导致方法 GetTwoInts 被执行,因为枚举永远不会被迭代。
回答by Pramod Sharma
This is an old post, but still thought of replying. IEnumerable is a behavior while Array is a data structure(Contiguous collection of elements with fixed size, facilitating accessing elements by indexes) . When an Array implements IEnumerable, it is supposed to depict IEnumerable inherent property also (of facilitating iteration over the collection).
这是一个旧帖子,但仍然想回复。IEnumerable 是一种行为,而 Array 是一种数据结构(具有固定大小的元素的连续集合,便于通过索引访问元素)。当数组实现 IEnumerable 时,它也应该描述 IEnumerable 固有属性(促进集合迭代)。
回答by ZunTzu
To complement the other answers, note that there is a performance differencebetween IList<T>and List<T>when executing a foreach statement.
为了补充其他答案,请注意执行 foreach 语句之间和执行时存在性能差异。IList<T>List<T>
That's because the iterator object returned by List<T>.GetEnumeratoris a value-type whereas the one returned by IList<T>.GetEnumeratoris a reference-type, and thus requires a memory allocation (see Enumerator of value type of list in c#).
这是因为返回的迭代器对象List<T>.GetEnumerator是值类型,而返回的迭代器对象IList<T>.GetEnumerator是引用类型,因此需要分配内存(请参阅c# 中列表的值类型枚举器)。
In my opinion, IList<T>is not a very good interface anyway. For instance calling Addcan throw (see Why array implements IList?). If you need encapsulation you'd be better off using IEnumerable<T>or IReadOnlyList<T>.
在我看来,IList<T>无论如何都不是一个很好的界面。例如调用Add可以抛出(请参阅为什么数组实现 IList?)。如果您需要封装,最好使用IEnumerable<T>或IReadOnlyList<T>。
回答by Billy Li
In addition to other answers, understanding the different between Enumerable vs List/Array when using LINQ can have huge performance impact. In short, Enumerable can be perceived as a query builder while List/Array is the result of the query.
除了其他答案之外,在使用 LINQ 时了解 Enumerable 与 List/Array 之间的差异会对性能产生巨大影响。简而言之,Enumerable 可以被视为查询构建器,而 List/Array 是查询的结果。
In the context of LINQ to SQL using EntityFramework, the former is just building the SQL query without executing it against the database nor loading any data into memory while the later is the opposite. That's why we would defer calling .ToList()until we need it in the memory to perform business logic.
在使用 EntityFramework 的 LINQ to SQL 上下文中,前者只是构建 SQL 查询,而不对数据库执行它,也不将任何数据加载到内存中,而后者则相反。这就是为什么我们会推迟调用,.ToList()直到我们在内存中需要它来执行业务逻辑。
In other context, LINQ expression returning IEnumerable will defer execution until .ToList()is called. Consider example below:
在其他上下文中,返回 IEnumerable 的 LINQ 表达式将推迟执行,直到.ToList()被调用。考虑下面的例子:
void Main()
{
var w1 = "AB".AsEnumerable();
Console.WriteLine($"W1: 1");
w1 = w1.Where(W1);
Console.WriteLine($"W1: 2");
w1 = w1.Where(W2);
Console.WriteLine($"W1: 3");
w1.ToList();
Console.WriteLine($"----------");
var w2 = "CD".AsEnumerable();
Console.WriteLine($"W2: 1");
w2 = w2.Where(W1);
Console.WriteLine($"W2: 2");
w2 = w2.ToList();
Console.WriteLine($"W2: 3");
w2 = w2.Where(W2);
Console.WriteLine($"W2: 4");
w2.ToList();
Console.WriteLine($"----------");
}
bool W1(char arg)
{
Console.WriteLine($"W1:{arg}");
return true;
}
bool W2(char arg)
{
Console.WriteLine($"W2:{arg}");
return true;
}
OUTPUT:
W1: 1
W1: 2
W1: 3
W1:A
W2:A
W1:B
W2:B
----------
W2: 1
W2: 2
W1:C
W1:D
W2: 3
W2: 4
W2:C
W2:D
----------
In first example, two .Where()is being "appended" and executed together at the end when .ToList()is called with item "A" going through the pipe first then item "B", hence seeing "AABB" in the output, while in the second example, the .Where()is executed every time if we call .ToList()immediately afterwards, hence seeing "CD" and then "CD" again, output twice. Therefore, every time an Enumerable is converted to a List or an Array will cost one O(n)iteration over all items in the collection which will have performance impact when the collection is large.
在第一个示例中,.Where()当.ToList()项目“ A”首先通过管道然后项目“ B”被调用时,两个被“附加”并在最后一起执行,因此在输出中看到“ AABB”,而在第二个示例中,.Where()如果我们.ToList()之后立即调用,则每次都会执行,因此再次看到“ CD”然后“ CD”,输出两次。因此,每次将 Enumerable 转换为 List 或 Array 时,都会对集合中的所有项目进行一次O(n)迭代,这会在集合较大时对性能产生影响。
Although we don't trend to write code this way calling .ToList()in between LINQ calls but it would happen more frequent when we factor code into reusable methods that return List/Arrayrather than IEnumerable.
虽然我们不倾向于以这种方式编写代码.ToList(),在 LINQ 调用之间调用,但是当我们将代码分解为返回List/Array而不是IEnumerable.
This however doesn't mean we should always operate on IEnumerable. As mentioned by towlson, that operations such as .Count()will cause iteration over the collection while a List or Array would have this info pre-calculated and therefore converting to List/Arraywould be more efficient if you plan to call .Count()multiple times. This is also why there is a .Countproperty on a List rather than a .Count()method to count it.
然而,这并不意味着我们应该始终对IEnumerable. 正如towlson所提到的,诸如此类的操作.Count()将导致对集合的迭代,而 List 或 Array 将预先计算此信息,因此List/Array如果您计划.Count()多次调用,则转换为会更有效。这也是为什么.Count在 List 上有一个属性而不是一个.Count()计算它的方法的原因。

