在 foreach 循环中无法识别对象类型

本文关键字:识别 对象 类型 foreach 循环 | 更新日期: 2023-09-27 18:32:51

所以,我今天遇到了一个奇怪的问题。

假设我有一个定义如下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 的定义,并且找不到接受 ojbect 类型的第一个参数的扩展方法 ForeColor。

object

不包含节点的定义,并且找不到接受 object 类型的第一个参数的扩展方法节点。

但是,如果我用TreeNode child更改var child,一切都按预期工作。

有人可以解释这种行为吗?

在 foreach 循环中无法识别对象类型

因为TreeNodeCollectionobject上只有一个枚举器(它实现IEnumerable,而不是IEnumerable<TreeNode>(,所以var变得object。自己键入变量,您的代码将编译:

foreach (TreeNode child in nodes)
{ }

如其他答案所述,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>()将忽略不属于您请求的任何类型。

如果你在MSDN上看,你会看到这个:

public class TreeNodeCollection : IList, ICollection, IEnumerable

请注意,它不使用泛型集合,因此您必须使用变量类型而不是 var,因为将使用object

树节点集合类