代码之家  ›  专栏  ›  技术社区  ›  Daniel Fortunov

使用LINQ to XML时避免暴露于NullReferenceException

  •  3
  • Daniel Fortunov  · 技术社区  · 14 年前

    我用一连串的电话 XElement.Element() 方法深入到XML文档并提取属性值:

    XElement root = ...;
    XNamespace ns = "...";
    var firstName = 
      root
        .Element(ns + "Employee")
        .Element(ns + "Identity")
        .Element(ns + "Name")
        .Attribute(ns + "FirstName");
    

    但是,由于传入文档尚未经过架构验证,因此格式错误的文档可能会导致 NullReferenceException 如果不存在任何预期的中间元素。

    有没有办法避免这种风险,同时保持代码简洁?

    我可以将上面的代码包装在 空引用异常 然而,这感觉是错误的,也不会明确指出故障发生在哪里。构建一个信息性错误消息将是手动的、冗长的、容易出错的,并且是一个维护风险。

    我应该用 XPath 相反,这样我可以检查一个空返回,然后很容易地构造一个错误消息,指示XPath表达式无法解析?

    2 回复  |  直到 14 年前
        1
  •  7
  •   Jon Skeet    14 年前

    一种选择是 Elements() 而不是 Element() -如果找不到元素,将生成空序列。使用中的扩展方法 Extensions ,可以从一系列元素 元素序列-属性也是如此。所以:

    var firstName = 
      root
        .Elements(ns + "Employee")
        .Elements(ns + "Identity")
        .Elements(ns + "Name")
        .Attributes(ns + "FirstName")
        .FirstOrDefault();
    

    在那里 请注意,这两个片段之间的区别-这将找到第一个匹配的属性,即使它来自(比如)第二个Employee元素中第三个Identity元素中的first Name元素。这可能是你的问题,也可能不是。

    (只是检查一下,您确定需要属性上的名称空间吗?与元素不同,属性不会继承“默认”命名空间。在名称空间上使用属性比在元素上使用属性要难得多。)

        2
  •  1
  •   corvuscorax    14 年前

    可以定义扩展名方法来包装空检测。像这样的东西,例如:

    public static class XmlExtender
    {
       public static XAttribute AttributeOrDefault(this XElement el, XName name, string defValue)
       {
          var v = el.Attribute(name);
          return v == null ? new XAttribute(name, defValue) : v;
       }
    
       public static string AttributeValue(this XElement el, XName name, string defValue)
       {
          var v = el.Attribute(name);
          return v == null ? defValue : v.Value;
       }
    }
    

    可以这样使用:

    var firstName = root.ELement("elname")
                        .AttributeOrDefault("attrName", "N/A").Value;
    

    或者这个:

    var firstName = root.Element("elname")
                        .AttributeValue("attrName", "N/A");