ListItemCollection上的隐式类型不可能使用foreach,但可能使用for循环

时间:2012-10-24 20:15:44

标签: c# asp.net implicit

ListBox控件具有ListItemCollection类型的Items属性。

我理解为什么我不能写

foreach (var item in ShipperListBox.Items)
{
    if (item.Selected) count++;
}

但是必须写

foreach (ListItem item in ShipperListBox.Items)
{
    if (item.Selected) count++;
}

这与ListItemCollection实施IEnumerable而不是IEnumerable<ListItem>(如this question中所述)有关。

但我没有得到的是为什么以下没有问题。

for (int i = 0; i < ListBox1.Items.Count; i++)
{
    if (ListBox1.Items[i].Selected) count++;
}

ListItemCollection的哪一部分让编译器清楚ListBox.Items[i]的类型为ListItem

3 个答案:

答案 0 :(得分:1)

因为ListItemCollection实现了返回ListItem的{​​{3}}。

这与IEnumerable分开。

答案 1 :(得分:0)

这是.OfType<ListItem>().Cast<ListItem>()明确存在的一部分:

  

Cast(IEnumerable)方法允许通过提供必要的类型信息在非泛型集合上调用标准查询运算符。例如,ArrayList不实现IEnumerable,但通过在ArrayList对象上调用Cast(IEnumerable),可以使用标准查询运算符来查询序列。 (source)

所以你可以写

foreach (var item in ShipperListBox.Items.OfType<ListItem>())
{
    if (item.Selected) count++;
}
但是,我无法告诉你原因。

答案 2 :(得分:0)

ListItemCollection.GetEnumerator确实返回一个自.NET 1.0以来使用的枚举数,它将对象作为值返回。 foreach pattern(正如Eric Lippert更详细地解释的那样)需要通过GetEnumerator方法返回对象返回的枚举器。

使用var时,编译器会将循环变量的类型推断为对象,因为Enumerator的Current只返回一个对象。

public interface IEnumerator
{
    bool MoveNext();
    object Current { get; }
    void Reset();
}

但是当你使用foreach(ListItem item in xxx)时......编译器会自动为你从对象中添加一个强制转换。你可以尝试foreach(在新对象[] {“str”,1}中的字符串str),这将导致InvalidCastException。 var关键字没有神奇之处。它只是在不做任何额外魔法的情况下推断出类型。

当你期望循环中出现ListItem时,你应该清楚地写出来。从枚举器的方法签名中,不清楚它将返回什么对象。您必须告诉编译器您期望的类型。不使用var关键字的另一个原因是,因为代码的读者也无法推断出循环变量的类型。