【问题标题】:Extension method for Null handling not working on linq for xmlNull 处理的扩展方法不适用于 linq for xml
【发布时间】:2013-03-01 08:45:39
【问题描述】:

我在尝试获取 xml 标记的值时遇到了 nullexception 问题,该标记位于可能不存在的子树下。

扩展处理程序在现有子树上找不到标签时效果很好,但在不存在的子树中查找标签时似乎无法处理。

在这种情况下,子树是 summaryData,它可能存在也可能不存在,并且尝试获取 addressLine1 是它无法处理 null 的地方,我收到错误

System.NullReferenceException 发生,Message=Object reference not 设置为对象的实例。

这里是xml,为了清楚起见,删减了,但结构是正确的:

 <record>
  <accounts>
    <account >
    </account >
  </accounts>
  <summaryData>
    <Date>2013-02-04</Date>
    <address >
      <city>Little Rock</city>
      <postalCode>00000</postalCode>
      <state>AR</state>
      <addressLine1>Frank St</addressLine1>
    </serviceAddress>
  </summaryData>

</record>

我的 C# 代码是:

 xmlDoc.Descendants("account")
                //select (string)c.Element("account") ;
                select new
                {
                    //this works fine
                    Stuffinxml = c.Element("stuffinxml").Value,
                    //this field may not be there, but the handler handlers the exception correctly here when it as the correct root (account)
                    otherstuff = CustXmlHelp.GetElementValue(mR.Element("otherstuff")),
                    //this is the problem, where the summaryData root does not exist (or moved somewhere else)
                    street_address = GetElementValue(c.Element("summaryData").Element("serviceAddress").Element("addressLine1"))

                };

我处理 null 的扩展方法是:

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

任何帮助将不胜感激,因为当子树不存在时,我不明白为什么它会失败。

【问题讨论】:

  • 您传入 c.Element("summaryData").Element("serviceAddress").Element("addressLine1"),空值是否来自缺少这些中间元素中的任何一个。您方法中的 null 检查仅检查最后一个(实际传递给 null 方法的那个)
  • 您的示例 xml 无效 - address 标签 - 是拼写错误还是实际记录?
  • 你说得对,我删减了太多,去掉了结束地址标签。错字。

标签: c# xml linq-to-xml


【解决方案1】:

摘要数据可能存在也可能不存在

这就是为什么。在嵌套调用时,您必须对它们all进行空检查。

其中任何一个都可以为空:

c.Element("summaryData").Element("serviceAddress").Element("addressLine1")

如果没有复杂的条件,就没有一个不错的方法来解决它:

street_address = c.Element("summaryData") != null
    ? c.Element("summaryData").Element("serviceAddress") != null
        ? GetElementValue(c.Element("summaryData").Element("serviceAddress").Element("addressLine1"))
        : string.Empty
    : string.Empty;

【讨论】:

  • 好的,有道理。我想我也可以将summaryData元素传递给扩展方法,如果它不为null,则在扩展方法中挖掘addressLine1,但不确定是否更干净。
  • @user1644147 你可以而且它会更干净,但是那个方法只会对 summaryData 元素真正有用,它不会是通用的。最好让它像上面一样:)
【解决方案2】:

如果summaryDate 元素不存在则

c.Element("summaryData").Element("serviceAddress").Element("addressLine1")

将抛出 NullReferenceException,因为您试图在空引用 (c.Element("summaryData")) 上调用 Element()

【讨论】:

    【解决方案3】:

    如前所述,您的例外是由于您传递了多个嵌套查询

    c.Element("summaryData").Element("serviceAddress").Element("addressLine1")
    

    是写作的等价物:

    var x1 = c.Element("summaryData");
    var x2 = x1.Element("serviceAddress")
    var x3 = x2.Element("addressLine1")
    

    因此,如果cx1x2 中的任何一个为空,您将获得NullReferenceException

    使用多个空检查的纯LINQ 解决方案的一种可能替代方法是使用XPath 来构建表达式。

    使用XPath,您可以编写表达式,而不是在每个级别进行空检查:

    street_address = GetElementValue(c.XPathSelectElement("/summaryData/serviceAddress/addressLine1"))
    

    这将评估整个表达式,如果它不完整存在,它将返回 null,但不会像您的纯 LINQ 查询那样抛出异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-16
      • 1970-01-01
      • 1970-01-01
      • 2019-04-23
      • 2015-12-17
      • 2019-09-23
      • 1970-01-01
      相关资源
      最近更新 更多