为什么在XmlNodeList循环中,var会推断为object类型而不是XmlNode类型?

9
如果要像这样循环遍历XmlNodeList:
foreach (XmlNode foo in xmlNodeList) {string baa = foo.Attributes["baa"].Value;}

一切都按预期进行 - foo 明显是类型为 XmlNode 的,VS.NET IDE 显示了方法和字段。

另一方面

foreach (var foo in xmlNodeList) { string baa = foo.Attributes["baa"].Value; }

这段代码无法编译,因为foo的类型是object。类型推断有点起作用,但是会推断出object

显然,XmlNodeList的元素不是一个定义的类型,但将它们分配给XmlNode而不是var会隐式执行某些操作(强制转换或拆箱)。

第一个问题:背后的机制是什么?

第二个(相关的)问题:如何找到可以在这种循环中使用的类型?VS.NET IDE是否有帮助?


1
您可能希望使用system.xml.linq命名空间中的类,因为它们实现了泛型版本IEnumerable等。当使用这些类时,var应该被正确推断。但是,结果可能会有所不同。 - Chris Dunaway
@Chris:谢谢你的提示 - 我会检查的。 - Olaf
+1,我正想问同样的问题 :-) - Eric J.
3个回答

10

XmlNodeList仅实现了非泛型的IEnumerable接口,而不是像IEnumerable<XmlNode>这样使用泛型。这会导致其元素无法进行强类型化,直到您进行适当的转换,因此编译器别无选择,只能将隐式类型声明映射为object,并在foreach循环中进行遍历。

如果您坚持使用var关键字,则可以这样将xmlNodeList的元素转换:

foreach (var foo in xmlNodeList.Cast<XmlNode>())
{
    string baa = foo.Attributes["baa"].Value;
}

但是那很丑,而且需要更多的按键操作。你可以直接明确声明XmlNode foo,然后让foreach在运行时将其强制转换。


非常感谢,已经明白了!我不想要丑陋的代码,但正如我在评论 Jon 的问题中所写的那样,这个问题部分上是实际应用的:如果 Resharper 给了我 'var',那么找到真正的类型的最快方式是什么? - Olaf
1
正如Daniel Hilgarth所指出的那样,最简单的方法是查看文档。 - BoltClock

4
正如BoltClock所指出的那样,XmlNodeList只实现了IEnumerable接口。 foreach循环会在后台自动为您执行转换,因此以下代码等效:
List<object> values = new List<object> { "x", "y", "z" };
foreach (string x in values)
{
    ...
}

这是完全合法的,它会对每个值执行转换(当然可能会抛出异常)。

我不太清楚你在第二个问题中的意思 - 但我建议您在循环中明确使用XmlNode。如果您真的想使用var,您可以编写以下代码:

foreach (var foo in xmlNodeList.Cast<XmlNode>())

但我觉得这有些杀鸡焉用牛刀的感觉...


谢谢,IEnumerable vs. IEnumerable<T>解释得很清楚!我的第二个问题是:在这种情况下,找到我需要的项目类型(在本例中为'XmlNode')的最快方法是什么?Resharper给了我“var”,所以我想知道VS.NET是否在其智能感知中隐藏了它。 - Olaf
3
@Olaf:不行,这里无法使用Intellisense,因为信息根本不存在。你需要知道自己在做什么——当然,这是必须的 :) - Jon Skeet
这就是我想知道的(信息只是不在那里)。谢谢你帮我知道我在做什么! - Olaf

4

XmlNodeList在.NET Framework支持泛型之前就存在了。因此,它只实现了非泛型接口IEnumerable而不是泛型IEnumerable<T>

要知道这个列表中可以包含哪些类型,您需要阅读文档。最好的方法是使用索引器

顺便提一下:自Visual Studio 2005发布以来,IDE已经不再称为VS.NET了 :-) 它只被称为VS。


谢谢,还有关于VS.NET的提示(我们仍在内部使用它)! - Olaf

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