来自IEnumerable的foreach中特定类型的对象
我正在使用只实现非通用IEnumerable
和ICollection
的旧集合对象。 当我尝试将此对象与foreach
在foreach表达式的LHS上给出更具体的类型时,该对象究竟发生了什么?
// LegacyFooCollection implements non-generic IEnumerable LegacyFooCollection collection = GetFooCollection(); foreach (Foo f in collection) { // etc. }
我知道(因为我已经尝试过了)当collection
所有东西都是Foo
类型时,这是安全的,但如果失败会发生什么?
C#编译器为您隐式执行强制转换。 在铸造方面(但仅限于那些术语1 ),它相当于:
foreach (object tmp in collection) { Foo f = (Foo) tmp; ... }
请注意,通用集合也会发生这种情况:
List
这一点在C#4规范的第8.8.4节中有详细说明。
如果您使用的是.NET 3.5或更高版本,并且只想选择相应类型的项目,则可以使用Enumerable.OfType
:
LegacyFooCollection collection = GetFooCollection(); foreach (Foo f in collection.OfType()) { // etc. }
对于LegacyFooCollection
,这可能不是必需的,但是当您尝试查找(比方说)表单中的所有TextBox
控件时,它可能很有用。
1差异是:
- 在原始代码中,
f
是只读的; 在“转换”中它是可写的 - 在原始代码中,如果捕获
f
您将(当前)捕获所有迭代中的单个变量,而不是“转换”中每次迭代的单独变量
此代码将创建可枚举到Foo
的每个元素的运行时类型转换(强制转换)。 所以,如果你做了foreach (string f in collection)
你会在运行时得到一个ClassCastException
,它第一次尝试将Foo
引用转换为String
引用。
它每次都会投射。 foreach
循环只是使用IEnumerator
方法。
ForEeach中的简短演员:
foreach (MenuItem menuItem in treeView.ContextMenu.Items.Cast().OfType