【发布时间】:2010-09-09 19:16:39
【问题描述】:
static void Main(string[] args)
{
List<int> listArray = new List<int>();
listArray.Add(100);
foreach (int item in listArray)
Console.WriteLine(item);
}
a) 当foreach 语句调用listArray's IEnumerable<int>.GetEnumerator() 实现时,它是通过listArray.GetEnumerator() 或IEnumerable<int>.GetEnumerator() 或IEnumerable.GetEnumerator() 调用它吗?
b) 同样,当foreach 引用listArray's IEnumerable<int>.GetEnumerator() 返回的对象时,它是通过IEnumerator 还是IEnumerator<int> 引用类型引用该对象?
谢谢
编辑:
我的一些问题会引用这段文字:
o 对类型 X 执行成员查找 带有标识符 GetEnumerator 并且没有 类型参数。如果成员查找 不产生匹配,或者它 产生歧义,或产生 不是方法组的匹配项, 检查可枚举接口为 如下面所描述的。推荐 如果成员发出警告 查找产生任何东西,除了 方法组或不匹配。
o 使用 生成的方法组和 空参数列表。如果过载 决议导致不适用 方法,导致歧义,或 结果是一个最好的方法,但是 该方法是静态的还是非静态的 public,检查一个可枚举的 界面如下所述。它是 建议发出警告 如果重载决议产生 除了明确的公众之外的任何东西 实例方法或不适用 方法。
o 如果返回类型 E 的 GetEnumerator 方法不是一个类, 结构或接口类型,错误是 生产,没有进一步的步骤 采取了。
o 成员查找在 E 上执行 带有标识符 Current 和 no 类型参数。如果成员查找 不产生匹配,结果是 错误,或者结果是什么 除了公共实例属性 允许读取,产生错误 并且没有采取进一步的步骤。
o 成员查找在 E 上执行 标识符 MoveNext 并且没有类型 论据。如果成员查找 不产生匹配,结果是 错误,或者结果是什么 除了方法组,错误是 生产,没有进一步的步骤 采取了。
o 重载解决方案在 方法组为空 参数列表。如果重载决议 导致没有适用的方法, 导致歧义,或导致 一个最好的方法,但那个方法 是静态的或不公开的,或者它的 返回类型不是 bool,错误是 生产,没有进一步的步骤 采取了。
o 集合类型是 X, 枚举类型为 E,元素 type 是当前的类型 财产。
否则,检查可枚举接口: o 如果恰好存在一种类型 T 使得存在隐式 从 X 到接口的转换 System.Collections.Generic.IEnumerable, 那么集合类型就是这个 接口,枚举类型是 界面 System.Collections.Generic.IEnumerator, 元素类型为T。
否则,如果有多个这样的类型 T,则 产生错误并且没有进一步的步骤 被拍了。
否则,如果存在从 X 到 System.Collections.IEnumerable 接口,则集合类型为 这个接口,枚举类型是 界面 System.Collections.IEnumerator 和 元素类型是对象。
否则,将产生错误并且没有进一步的步骤 拍摄。
1)
引用 Eric Lippert 的话:
选项(1)是正确的。请注意,这 表示返回的枚举数是 一个未装箱的可变结构。
这是一个可变结构的事实 如果你这样做会产生非常真实的效果 像路过一样愚蠢的事情 结构就好像它是一个 参考类型;它将被复制 价值,而非参考。
来自http://en.csharp-online.net/ECMA-334:_15.8.4_The_foreach_statement:
foreach (V v in x) 嵌入语句
然后扩展为:
{ E e = ((C)(x)).GetEnumerator(); try { V v; while (e.MoveNext()) { v = (V)(T)e.Current; embedded-statement } } finally { … // Dispose e } }变量 e 对 or 不可见 可访问表达式 x 或 嵌入式声明或任何其他来源 程序代码。
在listArray的情况下,返回的枚举数被保存(即它的值被保存)在变量e中(因此变量e是一个可变结构)。但是根据上面的摘录,e是无法访问我的源代码,那么我将如何传递这个结构(除非我编写的代码手动执行 foreach 语句自动执行的操作)?
2)
成员查找在 E 上执行,标识符为 Current,没有类型参数。如果 成员查找不产生匹配,结果是错误,或者结果是任何东西 除了允许读取的公共实例属性之外,会产生错误并且不会 采取进一步措施。
似乎如果我们在类(X)本身中实现GetEnumerator,那么Current也应该在类(E)本身中实现(因此E不应该显式实现@ 987654344@ ),因为在成员查找(在 E 上,标识符为 Current )不产生匹配的情况下,编译器不会费心检查 IEnumerator<T> / IEnumerator 接口?
3)
如果只有一种类型 T 存在从 X 到 接口 System.Collections.Generic.IEnumerable,那么集合类型就是这个 接口,枚举类型为接口 System.Collections.Generic.IEnumerator,元素类型为T。
根据上述,如果foreach 必须检查IEnumerable<T> 接口,那么foreach 将始终使用IEnumerator<T> 版本的Current?因此,如果E 显式实现了IEnumerator<T> 版本的Current,并且如果它还在类本身中实现了另一个版本的Current,那么foreach 将始终调用IEnumerable<T> 版本的Current?
4)
GetEnumerator 方法被记录为返回以下之一:
其中一个(如复数形式)是什么意思?您提供的链接说 GetEnumerator (由 List<T> 实现)仅返回 struct 类型。
5)
g.集合类型为X,枚举类型为E,元素类型为Current属性的类型
也许是一个无用的问题——根据上面,foreach 不会检查某些用户定义的集合实际存储的元素类型,而是假设元素的类型与Current 返回的类型相同财产?
【问题讨论】:
-
您是否考虑过编写一个简单的测试来找出自己?编写一个实现
IEnumerable.GetEnumerator()和 GetEnumerator() 的类并传回不同的枚举器是非常简单的。 -
我已更新我的答案以解决您的其他问题。
标签: c#