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

JSB*_*ոգչ 9 c# generics ienumerable foreach

我正在使用只实现非泛型IEnumerableICollection.的遗留集合对象.当我尝试使用此对象并foreach在foreach表达式的LHS上给出更具体的类型时,该对象究竟发生了什么?

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

我知道(因为我已经尝试过了)当一切都collection属于类型时,这是安全的Foo,但如果失败会发生什么?

Jon*_*eet 15

C#编译器为您隐式执行强制转换.在铸造方面(但仅限于那些术语1)它相当于:

foreach (object tmp in collection)
{
    Foo f = (Foo) tmp;
    ...
}
Run Code Online (Sandbox Code Playgroud)

请注意,通用集合也会发生这种情况:

List<object> list = new List<object> { "hello", "there", 12345 };

// This will go bang on the last element
foreach (string x in list) 
{
}
Run Code Online (Sandbox Code Playgroud)

这一点在C#4规范的第8.8.4节中有详细说明.

如果您使用的是.NET 3.5或更高版本,并且只想选择相应类型的项目,则可以使用Enumerable.OfType:

LegacyFooCollection collection = GetFooCollection();
foreach (Foo f in collection.OfType<Foo>())
{
    // etc.
}
Run Code Online (Sandbox Code Playgroud)

这对于a来说可能不是必需的LegacyFooCollection,但是当你试图找到(比如说)TextBox表单中的所有控件时它会很有用.


1差异是:

  • 在您的原始代码中,它f是只读的; 在"转换"中,它是可写的
  • 在原始代码中,如果捕获,f您将(当前)捕获所有迭代中的单个变量,而不是"转换"中每次迭代的单独变量

  • 不,实际上,它不等同于那个。首先,语法是`foreach (object tmp in collection)`。其次,您可以在示例中为 `f` 分配任何想要的内容,而在 OP 的示例中则不能这样做,因为他的 `f` 是一个 foreach 迭代变量。(一个微妙但重要的区别。) (2认同)