为什么必须在foreach C#中显式声明ListItem

时间:2015-03-02 22:58:14

标签: c# asp.net

如果listControl是ListControl对象(如DropDownList),我很困惑为什么这段代码无法编译:

foreach (var item in listControl.Items) {
    item.Value = string.empty;
}

编译器认为item属于object类型。如果我用var替换ListItem,明确声明变量,它就有效。 Items属性为ListItemCollection,实现IEnumerable。编译器是否应该能够告诉集合中的对象是ListItem类型的对象?

3 个答案:

答案 0 :(得分:6)

这是一种奇怪的行为,因为正如您所指出的,ListItemCollectionListItem的集合。这似乎与在C#支持的泛型之前实现的事实相关。因此它实现了IEnumerable而不是IEnumerable<ListItem>,并且无法确定正确的类型。

我建议用这种方式重写你的循环:

foreach (ListItem item in listControl.Items) {
    item.Value = string.empty;
}

查看this question了解更多信息。

答案 1 :(得分:4)

编译器无法在编译时告诉您,因为这些项是对象。它将使用任何类型进行编译,例如,如果您使用

foreach(int item in collection)

它会编译,因为从object到int的转换是有效的,但它会在运行时抛出异常,因为类型不兼容。

答案 2 :(得分:1)

原始问题

  

Items属性是一个ListItemCollection,它实现了IEnumerable。编译器不应该能够告诉集合中的对象是ListItem类型吗?

简答

否。编译时类型为object,因为这是IEnumerator.Current的编译时类型。 var关键字仍然是静态输入的!如果ListItemCollection已实施IEnumerable<T>而不是IEnumerable,则编译器会了解更多信息。

更多详情

From the docs

  

... System.Collections.IEnumerator [is]用于从集合中获取项目。

当您使用foreach循环时,您隐式使用IEnumerator接口。因此,当您访问每个项目时,Current属性returns an object即使在运行时位于ListItem下也是如此。

重要的是,var关键字仍然是静态的,因此您可能编写了以下代码。您是否希望编译器能够理解这一点:

foreach (var item in (object)listControl.Items) {
    item.Value = string.empty;
}  

您的var是静态类型的object。如果您希望运行时确定它是ListItem,那么您必须使用dynamic而不是var