【发布时间】:2011-04-06 11:28:05
【问题描述】:
IEnumerable 中不允许索引是否有任何具体原因。
我找到了解决问题的方法,但只是想知道为什么它不允许索引。
谢谢,
【问题讨论】:
标签: c# list generics ienumerable
IEnumerable 中不允许索引是否有任何具体原因。
我找到了解决问题的方法,但只是想知道为什么它不允许索引。
谢谢,
【问题讨论】:
标签: c# list generics ienumerable
因为不是。
索引由IList 覆盖。 IEnumerable 的意思是“我拥有 IList 的一些权力,但不是全部。”
某些集合(如链表)无法以实用的方式建立索引。但是可以逐项访问它们。 IEnumerable 用于这样的集合。请注意,集合可以同时实现 IList 和 IEnumerable(以及许多其他)。你一般只会找到IEnumerable作为函数参数,这意味着函数可以接受任何类型的集合,因为它只需要最简单的访问模式。
【讨论】:
Names 不是一个类,而是一个扩展 IEnumerable 接口以允许索引的接口,就像 IList 扩展 IEnumerable 一样。
IEnumerable<T> 接口不包含indexer,您可能会将其与IList<T> 混淆
如果对象确实是IList<T>(例如List<T> 或数组T[]),请尝试将其引用类型为IList<T>。
否则,您可以使用myEnumerable.ElementAt(index),它使用Enumerable.ElementAt 扩展方法。这应该适用于所有 IEnumerable<T>s 。
请注意,除非(运行时)对象实现IList<T>,否则这将导致所有第一个index + 1 项目被枚举,除了最后一个被丢弃。
编辑:
作为解释,IEnumerable<T> 只是一个表示“暴露枚举器的接口”的接口。一个具体的实现很可能是某种内存列表,确实允许按索引快速访问,也可能不允许。例如,它可能是无法有效满足此类查询的集合,例如链表(如 James Curran 所述)。它甚至可能完全是没有分类的内存中数据结构,例如迭代器,其中项目是按需生成('yielded')的,或者由从某些获取项目的枚举器远程数据源。因为IEnumerable<T> 必须支持所有这些情况,所以索引器被排除在其定义之外。
【讨论】:
ElementAt 的实现足够智能,可以检查对象是否可以转换为IList,如果可以直接索引而不是逐项遍历。
您可以使用 ToList 转换为列表。例如,
SomeItems.ToList()[1]
【讨论】:
如果您的可枚举类型是如下字符串,则可以使用索引
((string[])MyEnumerableStringList)[0]
【讨论】:
一个原因可能是IEnumerable 可能包含未知数量的项目。某些实现会在您对其进行迭代时生成项目列表(有关示例,请参阅yield)。这在使用索引访问项目时效果不佳。这将要求您知道列表中至少有那么多项目。
【讨论】:
[]-操作符被解析为访问属性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
同时查看[]-运算符的语法:
//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> 接口设计得很糟糕。或者更确切地说,在我看来,缺少 an interface "between" IEnumerable<T> and IList<T>(随机访问,但没有修改)是 BCL 中的一个不幸的疏忽。
【讨论】:
我有一列不允许空值,我正在插入空值。
【讨论】:
您可以将IEnumerable 与this 结合使用:
public interface IWorksheets : IEnumerable
{
IWorksheet this[int index] { get; }
IWorksheet this[string name] { get; }
}
然后你可以使用foreach和索引:
IWorksheet worksheet= excelWorkbook.Worksheets["Sheet1"]
foreach (IWorksheet worksheet in excelWorkbook.Worksheets)
{
【讨论】: