Aug

19

Object Confusion with LINQ to XML

Posted by Keith McMillan

August 19, 2010 | Leave a Comment

I’ve been working recently with C#.NET, and in particular had an interesting experience with LINQ to XML. For those unfamiliar with LINQ, the idea is to apply sql-like syntax to a number of areas of the C# language, including XML documents, object, and of course, actual SQL data. Most interestingly, you can combine data from more than one of these sources.  I saw some particularly surprising results when I accessed the resulting collection of objects.

I was working with an XML document, and using LINQ to create C# objects for me. When I initialized the application, I read the XML file, and then used the resulting list. The code looked like this:

XElement document = XElement.Load(“Horses.xml”);

var Field = from horse in document.Elements(“horse”)
select new Horse(horse.Attribute(“name”).Value,
Convert.ToInt32(horse.Attribute(“number”).Value),
Convert.ToInt32(horse.Attribute(“odds”).Value));

As you can see, I was loading a file called “Horses.xml”, and then taking the attributes “name,” “number” and “odds” and insert them into a Horse object.  If you can’t tell by now, I was working with a horse racing simulation program.  Later in the program, I needed to set a winning horse number:

var list = from horse in Field
where horse.Number == horseNumber
select horse;

The curious thing about this code was that I was getting a different Horse object every time I executed the query!  How could that be? The list was only read once, when I created the program object.

It turns out that the value I gave to xmlHorses wasn’t the result of executing the LINQ query, it was the query itself. When I accessed the variable, the query was run, and the query was run each time I accessed the variable.  This meant that I got a new list,with new Horse objects, even though what I’d intended was to just create the list of horses once.

How did I handle this? It’s probably an inelegant solution, but the one I opted for was to simply take that Field variable, iterate it an insert the resulting Horses into a new list I could use later. That way, I’d only execute the query when I first built the list:

XElement document = XElement.Load(“Horses.xml”);

var xmlHorses = from horse in document.Elements(“horse”)
select new Horse(horse.Attribute(“name”).Value,
Convert.ToInt32(horse.Attribute(“number”).Value),
Convert.ToInt32(horse.Attribute(“odds”).Value));

// LINQ to XML recreates the list since it has a late binding. To make a list that has consistent elements,
// (rather than recreating the list every time we evaluate (we read the LINQ list once and put the
// results into a conventional list
List<Horse> newField = new List<Horse>();
Field = newField;

foreach (Horse horse in xmlHorses) {
newField.Add(horse);

If you’ve been wondering why you get a different object back each time you access a collection built by LINQ to XML, this may be why.


Comments

RSS feed | Trackback URI

Comments »

No comments yet.

Name (required)
E-mail (required - never shown publicly)
URI
Your Comment (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> in your comment.

Blogroll