不能用将索引应用于types为“System.Collections.Generic.IEnumerable <>”的expression式
在IEnumerable中不允许build立索引是否有任何特定的原因。
我find了解决问题的方法,但只是好奇地知道为什么它不允许build立索引。
谢谢,
因为不是。
索引由IList
覆盖。 IEnumerable
意味着“我有一些IList的权力,但不是全部。”
某些集合(如链接列表)不能以实用的方式进行索引。 但是可以逐项访问它们。 IEnumerable
用于这样的集合。 请注意,一个集合可以实现IList和IEnumerable(以及其他许多)。 你通常只能findIEnumerable
作为函数参数,这意味着函数可以接受任何types的集合,因为它所需要的只是最简单的访问模式。
IEnumerable<T>
接口不包含索引器 ,您可能会将其与IList<T>
混淆
如果对象确实是一个IList<T>
(例如List<T>
或一个数组T[]
),请尝试对IList<T>
进行引用。
否则,可以使用使用Enumerable.ElementAt扩展方法的myEnumerable.ElementAt(index)
。 这应该适用于所有IEnumerable<T>
s。 请注意,除非(运行时间)对象实现IList<T>
,这将导致所有第一个index + 1
项被枚举,除最后一个被丢弃外。
编辑:作为解释, IEnumerable<T>
只是一个接口,表示“暴露枚举器”。 一个具体的实现可能是某种内存列表, 它允许索引快速访问,或者它可能不是。 例如,它可能是一个集合,不能有效地满足这样的查询,如链接列表(如詹姆斯·库伦所提到的)。 它甚至可能根本就不是内存中的数据结构,比如迭代器,根据需要生成(“生成”)项目,或者由从某个远程数据源获取项目的枚举器。 由于IEnumerable<T>
必须支持所有这些情况,因此索引器不在其定义中。
一个原因可能是IEnumerable
可能包含未知数量的项目。 有些实现会在迭代时产生项目列表(请参阅yield
for samples)。 使用索引访问项目时效果不佳。 这会要求你知道列表中至less有很多项目。
接口的概念通常是公开一种基线合同,通过这种合同,在对象上执行工作的代码可以保证由该对象提供的某些function。 在IEnumerable<T>
的情况下,该合同恰好是“您可以逐个访问我所有的元素”。
根据这个合同可以单独编写的方法有很多种。 请参阅Enumerable
类以获取大量示例。
但是只要一个具体的一个就可以了:思考Sum
。 为了总结一堆物品,你需要什么? 你需要什么合同? 答案很简单:只是看一眼每一件物品的方法,而已。 随机访问是没有必要的。 即使是所有项目的总数是没有必要的。
为IEnumerable<T>
接口添加一个索引器有两个方面是有害的:
- 要求上述合同的代码(访问一系列元素),如果它需要
IEnumerable<T>
接口,将是人为的限制,因为它不能处理任何没有实现索引器的types,即使处理这样的types应该真的在代码的能力范围内。 - 任何想要公开一系列元素但没有适当地提供通过索引提供随机访问的types(例如,
LinkedList<T>
,Dictionary<TKey, TValue>
)现在将不得不提供模拟索引的一些低效率手段,或者否则放弃IEnumerable<T>
接口。
所有这一切都在说,考虑到接口的目的是为了在给定的情况下提供最低要求的function的保证,我真的认为IList<T>
接口devise不好。 或者说,在IEnumerable<T>
和IList<T>
(随机访问,但没有修改) 之间缺less一个接口 ,这在BCL中是一个不幸的疏忽。
[]操作符parsing为访问属性this[sometype index]
,实现取决于元素集合 。
Enumerable-Interface首先声明集合应该是什么样子的蓝图。
以此示例来演示干净的接口分离的有用性:
var ienu = "13;37".Split(';').Select(int.Parse); //provides an WhereSelectArrayIterator var inta = "13;37".Split(';').Select(int.Parse).ToArray()[0]; //>13 //inta.GetType(): System.Int32
另外看一下[] -operator的语法 :
//example public class SomeCollection{ public SomeCollection(){} private bool[] bools; public bool this[int index] { get { if ( index < 0 || index >= bools.Length ){ //... Out of range index Exception } return bools[index]; } set { bools[index] = value; } } //... }
你可以使用索引,如果你的枚举types是像下面的string
((string[])MyEnumerableStringList)[0]