所以,我今天遇到了一个奇怪的问题。
假设我的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的定义,也没有扩展方法ForeColor可以找到类型为ojbect的第一个参数。
对象不包含节点的定义,也没有扩展方法可以找到接受类型为object的第一个参数的节点。
但如果我用var child
更改TreeNode child
,一切都会按预期进行。
有人可以解释这种行为吗?
答案 0 :(得分:7)
由于TreeNodeCollection
仅在object
上有一个枚举器(它实现了IEnumerable
,而不是IEnumerable<TreeNode>
),var
变为object
。自己键入变量,代码将编译:
foreach (TreeNode child in nodes)
{ }
答案 1 :(得分:2)
正如其他答案中所述,TreeNodeCollection
是object
个对象的集合。这是因为WinForms从一开始就是C#语言的一部分(.NET 1.1),并且在.NET 2.0之前不会添加泛型。出于向后兼容性的原因,他们没有改变类以实现IEnumerable<TreeNode>
。
正如您所发现的,处理它们的唯一方法是在TreeNode
循环中明确键入foreach
对象。这是因为在.NET 3.5之前没有添加var
。
另一个替代方案(虽然更详细)是获取所需类型的对象:
foreach (var child in nodes.OfType<TreeNode>())
正如我所说,这更加冗长,你更适合于明确地投射对象。但是,OfType
方法在您的保留曲目中是一个很好的方法。
<强>澄清强>
正如Patrick对答案的评论中提到的,另一种选择是.Cast<T>()
。但是,如果这样做,如果项目无法转换为指定类型,则抛出异常。在这样的情况下,你没事,因为根据创建集合的方式,你不会有任何不是TreeNode
的东西。但是,在其他集合中,可以使用基于超类等的其他类型。OfType<T>()
将忽略任何不属于您请求类型的内容。
答案 2 :(得分:1)
如果您查看MSDN,您会看到:
public class TreeNodeCollection : IList, ICollection, IEnumerable
请注意,它没有使用泛型集合,因此您必须使用变量类型而不是var,因为将使用object
。