0

I'm parsing an XElement object like this one

XElement teachers = new XElement("Teachers",
    new XElement("Teacher1", 
        new XAttribute("Age", 27)),
    new XElement("Teacher2",
        new XAttribute("Age", 60)),
    new XElement("Teacher3"),
        new XAttribute("Age", 50));

With this code:

IEnumerable<string> oldTeachers = from teacher in teachers.Elements()
                                        where int.Parse(teacher.Attribute("Age").Value) > 40
                                        orderby teacher.Name.ToString() ascending 
                                        select teacher.Name.ToString();

But i get a runtime error saying "Object reference not set to an instance of an object on the where line. What am I doing wrong?

EDIT:

I found the problem being the XElement declaration: the right one should have been this:

XElement teachers = new XElement("Teachers",
    new XElement("Teacher1", 
        new XAttribute("Age", 27)),
    new XElement("Teacher2",
        new XAttribute("Age", 60)),
    new XElement("Teacher3",
        new XAttribute("Age", 50)));
MaPi
  • 1,601
  • 3
  • 31
  • 64
  • I still would like to know where the Age of the this Teacher was being declared. Debugging didn't really helped – MaPi Jul 19 '14 at 15:09

2 Answers2

1

You can always print XML constructed by your code using XElement.ToString(), the first code added the Age="50" attribute to <Teachers> node :

<Teachers Age="50">
  <Teacher1 Age="27" />
  <Teacher2 Age="60" />
  <Teacher3 />
</Teachers>

And the 2nd code correctly adds the attribute to the <Teacher3> node :

<Teachers>
  <Teacher1 Age="27" />
  <Teacher2 Age="60" />
  <Teacher3 Age="50" />
</Teachers>

Just to make it clear, I got above XMLs using this simple line :

Console.WriteLine(teachers);
//or more verbose :
//Console.WriteLine(teachers.ToString());

FYI, you can avoid such exception by casting the XAttribute to int? (but in this case, getting exception seems better to make you aware that something wrong in the XElement construction :

IEnumerable<string> oldTeachers = from teacher in teachers.Elements()
                                  where (int?)teacher.Attribute("Age") > 40
                                  orderby teacher.Name.ToString() ascending
                                  select teacher.Name.ToString();
har07
  • 88,338
  • 12
  • 84
  • 137
0

First of all, you should not establish identity through the name of an element. The name of an element should be the name of a concept of what it represents. By naming your elements Teacher1, Teacher2, and Teacher3, you're making it harder to process than it should. If you need identity, add an attribute to your teachers.

var teachers = new XElement("Teachers",
    new XElement("Teacher",
        new XAttribute("Id", 1),
        new XAttribute("Age", 27)
    ),
    new XElement("Teacher",
        new XAttribute("Id", 2),
        new XAttribute("Age", 60)
    ),
    new XElement("Teacher",
        new XAttribute("Id", 3),
        new XAttribute("Age", 50)
    )
);

In LINQ to XML, if you needed the value of an Attribute/Element, you should cast to the appropriate type.

var oldTeachers =
    from teacher in teachers.Elements("Teacher")
    where (int)teacher.Attribute("Age") > 40
    orderby (int)teacher.Attribute("Id") ascending
    select "Teacher" + (int)teacher.Attribute("Id"); // or simply return the Id
Jeff Mercado
  • 129,526
  • 32
  • 251
  • 272