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

本文关键字:声明 foreach ListItem 为什么 | 更新日期: 2024-09-19 14:03:46

如果listControl是ListControl对象(如DropDownList:),我很困惑为什么不编译此代码

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

编译器认为item属于object类型。如果我用ListItem替换var,并显式声明变量,那么它就可以工作了。Items属性是实现IEnumerableListItemCollection。难道编译器不应该知道集合中的对象是ListItem类型的吗?

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

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

我建议这样重写你的循环:

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

查看此问题以了解更多信息。

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

foreach(int item in collection)

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

原始问题

Items属性是ListItemCollection,它实现IEnumerable。难道编译器不应该判断集合中的对象属于ListItem类型吗?

简短回答

没有编译时类型是object,因为它是IEnumerator.Current的编译时类型。var关键字仍然是静态键入的!如果ListItemCollection实现了IEnumerable<T>而不是IEnumerable,那么编译器将知道更多。

更多详细信息

来自文档:

a系统。集合。IEnumerator[用于从集合中获取项。

当您使用foreach循环时,您隐含地使用IEnumerator接口。因此,当您访问每个项时,Current属性返回一个对象,即使它在运行时是下面的ListItem

重要的是,var关键字仍然是静态的,因此您可能已经编写了以下代码。你希望编译器能解决这个问题吗:

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

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