我正在使用只实现非通用IEnumerable
和ICollection
的旧集合对象。当我尝试使用这个对象foreach
在foreach表达式的LHS上给出一个更具体的类型时,这个对象到底发生了什么?
// LegacyFooCollection implements non-generic IEnumerable
LegacyFooCollection collection = GetFooCollection();
foreach (Foo f in collection)
{
// etc.
}
我知道(因为我已经尝试过)当collection
中的所有内容确实属于Foo
类型时,这是安全的,但如果失败会发生什么?
答案 0 :(得分:14)
C#编译器为您隐式执行强制转换。就铸造而言(但仅 > 1 ),它相当于:
foreach (object tmp in collection)
{
Foo f = (Foo) tmp;
...
}
请注意,通用集合也会发生这种情况:
List<object> list = new List<object> { "hello", "there", 12345 };
// This will go bang on the last element
foreach (string x in list)
{
}
这一点详见C#4规范的第8.8.4节。
如果您使用的是.NET 3.5或更高版本,并且只想选择相应类型的项目,则可以使用Enumerable.OfType
:
LegacyFooCollection collection = GetFooCollection();
foreach (Foo f in collection.OfType<Foo>())
{
// etc.
}
LegacyFooCollection
可能不是必需的,但当您尝试查找(比方说)表单中的所有TextBox
控件时,它可能很有用。
1 差异是:
f
是只读的;在“转换”中它是可写的f
,您将(当前)捕获所有迭代中的单个变量,而不是“转换”中每次迭代的单独变量答案 1 :(得分:3)
此代码将创建可枚举的每个元素到Foo
的运行时类型转换(强制转换)。因此,如果您执行foreach (string f in collection)
,则会在运行时获得ClassCastException
,这是第一次尝试将Foo
引用转换为String
引用时。
答案 2 :(得分:0)
每次都会施放。 foreach
循环只使用IEnumerator
方法。
答案 3 :(得分:0)
ForEeach的简短演员:
foreach (MenuItem menuItem in treeView.ContextMenu.Items.Cast<object>().OfType<MenuItem>()
{
// Do stuff
}