在foreach循环中未识别到对象类型

3
今天我遇到了一个奇怪的问题。假设我有一个像这样定义的“TreeNode”:
```html TreeNode ```
TreeNode node = new TreeNode();
node.Nodes.Add(new TreeNode { Name = "aaa" });
node.Nodes.Add(new TreeNode { Name = "bbb" });

接着我调用一个递归方法

ColorNode(node.Nodes, Color.Green);

这个方法看起来就像这样:
void ColorNode(TreeNodeCollection nodes, System.Drawing.Color Color)
{
    foreach (var child in nodes)
    {
        child.ForeColor = Color;
        if (child.Nodes != null && child.Nodes.Count > 0)
            ColorNode(child.Nodes, Color);
    }
}

在那个foreach循环中,如果我保留var child,Visual Studio会报错:

对象不包含ForeColor的定义,也找不到接受类型为object的第一个参数的ForeColor扩展方法。

对象不包含Nodes的定义,也找不到接受类型为object的第一个参数的Nodes扩展方法。

但是,如果我将var child更改为TreeNode child,一切都按预期工作。
有人能解释这种行为吗?

3个回答

7

由于TreeNodeCollection只在object上有一个枚举器(它实现了IEnumerable而不是IEnumerable<TreeNode>),所以var变成了object。手动指定变量类型,你的代码就能编译通过:

foreach (TreeNode child in nodes)
{ }

这种情况在我使用 DataTable.Rows 时经常发生,有点让人烦恼。 - Jonesopolis
如果您喜欢在foreach中始终使用var,并且希望使转换显式化,则可以选择另一种方法:foreach (var child in nodes.Cast<TreeNode>()) { }。但是,您的解决方案当然更少打字,并且更符合.NET 1和旧的非泛型C#的精神。 - Jeppe Stig Nielsen
谢谢回答,但是krillgar很清楚地解释了为什么它不起作用。 - Zippy

3
正如其他答案所述,TreeNodeCollectionobject对象的集合。这是因为WinForms从一开始就是C#语言的一部分(.NET 1.1),而泛型直到.NET 2.0才被添加。出于向后兼容的原因,他们没有改变类来实现IEnumerable<TreeNode>
正如您发现的那样,唯一的处理方法是在foreach循环中将对象明确地声明为TreeNode。这是因为var直到.NET 3.5才被添加。
另一个选择是获取您想要的类型的对象,尽管更冗长:
foreach (var child in nodes.OfType<TreeNode>())

正如我所说的,这种方法更冗长,你最好直接显式地转换对象。不过,OfType 方法是你工具库中很好的一个方法。 澄清 正如在帕特里克的回答评论中提到的,另一个选择是使用 .Cast<T>()。不过,如果这样做,如果一个项目不能转换为指定的类型,就会抛出异常。在这种情况下,你没问题,因为根据集合创建的方式,你不会有任何不是 TreeNode 的东西。但是,在其他集合中,基于超类等原因可能会有其他类型。 OfType<T>() 将忽略任何不是你请求的类型的内容。

WPF中,TreeView项目也会发生同样的情况。这是否也适用于ItemsControl - Zippy
1
看起来是这样。从 ItemsControl 开始,通过 Items 属性向下查找,您会发现它是一个 ItemsCollection,出于某种原因它也不使用泛型。同样,这就是为什么 var 不起作用的原因,但我对他们避免使用泛型的理由在 WPF 中已经不再成立了。也许是为了与 WinForms 的方式保持一致,但这不是我赞同的设计决策。 - krillgar

1
如果您在 MSDN 上查看,您会看到这个: public class TreeNodeCollection:IList、ICollection、IEnumerable 请注意,它没有使用通用的集合,因此您必须使用变量类型而不是 var,因为 object 将被用作类型。
TreeNodeCollection 类的链接:TreeNodeCollection Class

完全正确,但我想知道为什么。krillgar的回答澄清了这一点。 - Zippy
当使用 foreach 进行枚举时,枚举器仅返回 object,因此 var 的类型变为 object,而不是 TreeNode。如前所述,这是由于该框架版本没有泛型所致。 - Ric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接