Aug
19
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
Comments »
Blogroll
- Ars Technica
- Dark Reading - IT Security
- Help Net Security
- InformIT
- SANS Internet Storm Center
- Schneier on Security - Dr. Bruce Schieier’s blog
- Security Info Watch
- What to Fix - Daniel Markham, fellow consultant
- Wired Gadget Lab
- Wordpress Documentation
- WordPress Planet
- Wordpress Support Forum
No comments yet.