Trouble with XElement Extension Method

I'm using the below code to pull out info from an XML file. But if node isn't present I get a NullReferenceException error. I thought that wasn't supposed to happen with using LINQ. But I'm very new to LINQ and XML for that matter. So I added an extention method I found from here. But I still get the error. Can someone tell me what I'm missing please?

using System;
using System.Text;
using System.Windows.Forms;
using System.Linq;
using System.Xml.Linq;

public static class XElementExtensionMethod
{
    public static string ElementValueNull(this XElement element)
    {
        if (element != null)
        {
            return element.Value;
        }
        else
        {
            return string.Empty;
        }
    }
}

namespace XMLReader
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            string file = @"c:\users\jim\desktop\XMLData - Copy.xml";
            XElement doc = XElement.Load(file);
            StringBuilder sb = new StringBuilder();

            var nodes = from node in doc.Elements("ClaimsSvcRs").Elements("ClaimDownloadRs")
                    select new
                    {
                        ClaimProbableAmount = (string)node.Element("ClaimsDownloadInfo").Element("ClaimsOccurrence").Element("ProbableIncurredAmt").Element("Amt").ElementValueNull()
                    };

        foreach (var node in nodes)
        {
            sb.Append("AMOUNT = ").Append(node.ClaimProbableAmount);
            MessageBox.Show(sb.ToString());
        }
    }
}
}
Jon Skeet
people
quotationmark

The problem is almost certainly not in ElementValueNull... it's that one of the earlier Element calls is returning null. You're calling an instance method (XContainer.Element()) and that's a perfectly ordinary instance method - if it's called on a null reference, that will throw an exception just like any other instance method will.

One option to avoid this is to use Elements repeatedly instead - that way you'll end up with an empty sequence, instead of a null reference. Use FirstOrDefault at the end to get a single XElement reference or null.

Additionally:

  • There's no benefit in using an anonymous type when you've got a single property. Just select the string itself.
  • There's no benefit in using a StringBuilder when you're calling ToString() on each iteration of the loop.

I would write your query as:

var amounts = doc.Elements("ClaimsSvcRs").Elements("ClaimDownloadRs")
                 .Select(x => (string) x.Elements("ClaimsDownloadInfo")
                                        .Elements("ClaimsOccurrence")
                                        .Elements("ProbableIncurredAmt")
                                        .Elements("Amt")
                                        .FirstOrDefault() ?? "");

(Note the lack of a need for your extension method - the explicit conversion to string will return null if the input is null, and then the null-coalescing operator will take care of using "" instead of null.)

people

See more on this question at Stackoverflow