Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does var infer type object and not XmlNode in XmlNodeList loop?

If one loops through an XmlNodeList like this

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

everything works as expected - foo is clearly of type XmlNode and the VS.NET IDE shows methods and fields.

On the other hand

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

is not compiling because here foo is of type object. Type inference sort of works but infers object.

Apparently, the elements of XmlNodeList are not of one defined type, but assigning them to XmlNode instead of var does something implicitly (casting or unboxing).

First question: what's the mechanism behind that?

Second (related) question: how to find the types one can use in this kind of loop? Does the VS.NET IDE help?

like image 920
Olaf Avatar asked Feb 03 '12 10:02

Olaf


3 Answers

XmlNodeList implements only the non-generic IEnumerable interface, and not something like IEnumerable<XmlNode> with generics. This prevents strong typing of its elements until you cast appropriately, so the compiler has no choice but to map the implicit type declaration to object in your foreach.

If you insist on using the var keyword, you can cast the elements of xmlNodeList like so:

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

But that's ugly, and requires more keystrokes anyway. You may as well just explicitly declare XmlNode foo, and let the foreach cast it for you on the fly.

like image 99
BoltClock Avatar answered Nov 03 '22 13:11

BoltClock


As BoltClock notes, XmlNodeList only implements IEnumerable.

The foreach loop automatically does casting for you behind the scenes, so this:

List<object> values = new List<object> { "x", "y", "z" };
foreach (string x in values)
{
    ...
}

is entirely legal, and performs a cast (which can throw an exception, of course) on each value.

It's not really clear to me what you mean by your second question - but I'd just recommend that you explicitly use XmlNode in your loop. If you really want to use var, you could write:

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

but that feels like overkill to me...

like image 4
Jon Skeet Avatar answered Nov 03 '22 11:11

Jon Skeet


XmlNodeList has been in the .NET Framework before it supported generics. Because of that, it implements only the non-generic interface IEnumerable and not the generic IEnumerable<T>.
To know which types can be in this list you need to read the documentation. The best way is the indexer.

BTW: The IDE hasn't been called VS.NET since Visual Studio 2005 was released :-) It is called VS only since then.

like image 4
Daniel Hilgarth Avatar answered Nov 03 '22 11:11

Daniel Hilgarth