来自IEnumerable的foreach中特定类型的对象

时间:2011-08-23 18:22:32

标签: c# generics foreach ienumerable

我正在使用只实现非通用IEnumerableICollection的旧集合对象。当我尝试使用这个对象foreach在foreach表达式的LHS上给出一个更具体的类型时,这个对象到底发生了什么?

// LegacyFooCollection implements non-generic IEnumerable
LegacyFooCollection collection = GetFooCollection();
foreach (Foo f in collection)
{
    // etc.
}

我知道(因为我已经尝试过)当collection中的所有内容确实属于Foo类型时,这是安全的,但如果失败会发生什么?

4 个答案:

答案 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
}