是否有任何特定原因为什么IEnumerable中不允许索引。
我找到了解决该问题的方法,但只是想知道为什么它不允许索引。
谢谢,
Answers:
因为不是。
索引涵盖在中IList
。 IEnumerable
表示“我拥有IList的某些功能,但不是全部。”
某些集合(如链接列表)无法以实际方式建立索引。但是可以逐项访问它们。 IEnumerable
适用于此类收藏。请注意,集合可以实现IList和IEnumerable(以及许多其他实现)。通常,您只能找到IEnumerable
一个函数参数,这意味着该函数可以接受任何种类的集合,因为它所需要的只是最简单的访问模式。
Names
它不是类,而是扩展IEnumerable接口以允许建立索引的接口,就像IList扩展IEnumerable一样。
该IEnumerable<T>
接口不包含索引器,您可能会将其与IList<T>
如果对象确实是IList<T>
(例如List<T>
或array T[]
),请尝试也对其类型进行引用IList<T>
。
否则,您可以使用myEnumerable.ElementAt(index)
使用Enumerable.ElementAt扩展方法的方法。这应该适用于所有人IEnumerable<T>
。请注意,除非(运行时)对象实现IList<T>
,否则这将导致index + 1
枚举所有前一项,除最后一项以外的所有项都将被丢弃。
编辑:作为说明,IEnumerable<T>
它只是一个表示“公开枚举数的接口”。一个具体的实现很可能是某种内存列表,它确实允许按索引快速访问,也可能不允许。例如,它可能是一个不能有效满足此类查询的集合,例如链表(James Curran提到)。它甚至可能根本不是一种内存中的数据结构,例如迭代器(根据需要生成(“屈服”)项目的)迭代器,或由从某个远程数据源获取项目的枚举器。由于IEnumerable<T>
必须支持所有这些情况,因此将索引器从其定义中排除。
ElementAt
足够智能,可以检查对象是否可以强制转换为对象IList
,如果可以,则直接索引而不是逐项遍历。
IOrderedEnumerable<T>
为什么吗?
原因之一可能是IEnumerable
可能包含未知数量的项目。某些实现会在您对其进行迭代时生成项目列表(请参阅参考资料yield
中的示例)。这对于使用索引访问项目不是很好。这将要求您知道列表中至少有那么多项目。
[] -operator解析为access属性this[sometype index]
,其实现取决于Element- Collection。
一个Enumerable-Interface声明一个Collection首先应该是什么样的蓝图。
以这个例子来演示干净的接口分离的有用性:
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;
}
}
//...
}
接口的概念通常是公开一种基线协定,通过它可以保证在对象上执行工作的代码具有该对象提供的某些功能。在的情况下IEnumerable<T>
,该合同恰好是“您可以逐一访问我的所有元素”。
可以单独基于此合同编写的方法种类很多。见Enumerable
类万吨的例子。
但是,仅将其中一项具体化为零:请考虑Sum
。为了总结一堆物品,您需要什么?您需要什么合同?答案很简单:仅是查看所有项目的一种方式,仅此而已。随机访问不是必需的。甚至不需要所有项目的总数。
在IEnumerable<T>
接口上添加索引器将对两种方式造成不利影响:
IEnumerable<T>
接口,将是人为限制的,因为它不能处理没有实现索引器的任何类型,即使处理这种类型也应该如此确实在代码功能范围内。LinkedList<T>
,Dictionary<TKey, TValue>
)将现在必须要么提供的一些效率低下手段模拟索引,否则放弃IEnumerable<T>
接口。综上所述,考虑到接口的目的是为了保证给定场景中所需的最低功能,我确实认为IList<T>
接口设计不良。或更确切地说,我认为BCL中缺少“IEnumerable<T>
和”之间的接口IList<T>
(随机访问,但没有修改),这是一个不幸的疏忽。