还是反过来呢?
我经常使用通用列表。但是我偶尔也会听到关于IEnumerables的说法,而且今天我真的不知道它们是用来做什么的,以及为什么我应该使用它们。因此,冒着在网络上永远标榜我的无知的风险,我谦卑地发布这个问题。
还是反过来呢?
我经常使用通用列表。但是我偶尔也会听到关于IEnumerables的说法,而且今天我真的不知道它们是用来做什么的,以及为什么我应该使用它们。因此,冒着在网络上永远标榜我的无知的风险,我谦卑地发布这个问题。
嗯,List<T>
实现了 IEnumerable<T>
接口...基本上,IEnumerable<T>
就是一系列项目的序列。你可以逐个阅读它们,这就是全部内容。
List<T>
是一个可变集合 - 你可以添加到它里面、从它中删除、对其进行排序等。它本身更加灵活,但是 IEnumerable<T>
允许你使用相同的代码来处理任何实现(如数组、链表、列表、使用 yield
语句返回的迭代器等)。
IEnumerable<T>
是不可变的,因此您可以在从类返回数据时使用此接口,因为知道不会添加或删除任何元素。尽管用户仍然可以对可枚举对象中包含的对象调用突变函数。 - Marcel GosselinIEnumerable<T>
接口不包含任何改变序列的方法,具体的实现可以是可变的,也可能是不可变的。如果一个方法签名声明返回 IEnumerable<Whatever>
,但实际上返回了一个 List<Whatever>
,那么调用代码可以轻易地将返回的对象强制转换成List<Whatever>
并修改列表内容。但是该方法签名确实 传达了结果应被当作只读来处理。 - Fredrik MörkIList<T>
,因此这并不是百分之百可靠的。 - recursiveIEnumerable<T>
转换为IList<T>
是合适的。例如,.Last
扩展方法在可能的情况下似乎会将其参数转换为IList<T>
;因此,可以在不必阅读前9999999个项目的情况下几乎即时地检索10000000个项目列表的最后一个项目。 - supercat首先,IEnumerable提供更通用的合同来表示可以迭代的事物集合,因此允许您遵守最小特权原则。换句话说,在只需要公开枚举行为的任务中,应优先使用IEnumerable而不是其派生类型。这是有益的,因为不必要地公开信息和/或行为会使您的API面临可能的意外用途,这可能会导致安全问题或API与其消费者之间的意外耦合。
其次,IEnumerable是枚举的抽象,而List是该抽象的一种实现。遵循可重用面向对象软件元素的设计模式的指导,编写抽象而不是实现有助于使应用程序更具弹性,因为它允许稍后更改实现而不影响使用代码。如果确实需要列表行为,则应直接公开IList而不是List。
List<T>
相对于 IEnumerable<T>
的最大优势如下:
IEnumerable<T>
上也很容易实现,但无法保证 O(1) 速度。在计数方面,由于 IEnumerable<T>
可以轻松表示无限列表,因此甚至无法保证真实答案。如果你只需要在 IEnumerable<T>
中暴露和实现的功能,那么你应该选择它。另一种选择是 IEnumerable<T> where T : IFoo
,如果你想要能够迭代实现接口 IFoo
的对象。然而,如果你需要像 List<T>
所暴露的 Count
等属性,那么你应该选择它。找到最低公共分母并选择它,因为这使得你的方法更加通用且易于使用。
IEnumerable 具有干净的只读和“可枚举”或“可查询”的语义。而使用 List,似乎允许任何人修改它:)。
IEnumerable的一个优点还没有被提到:逆变性。一个期望IEnumerable(Of Car)的程序会非常高兴地接受IEnumerable(Of HondaCivic),这意味着它也会接受IList(Of HondaCivic)。相比之下,一个期望IList(Of Car)的程序将不会满足于IList(Of HondaCivic)。如果Microsoft IList是从只读IReadableByIndex接口派生而来的,那么期望IReadableByIndex(Of Car)的代码将非常高兴地接受IReadableByIndex(Of HondaCivic),但这已经是过去时了。