扩展方法对 XML LINQ 中的空值处理不起作用

3

尝试获取一个可能不存在的子树下的xml标签值时,我遇到了nullexception问题。

当扩展处理程序在现有子树上找不到标签时,它运行良好,但似乎无法处理在不存在子树中寻找标签的情况。

在这种情况下,子树是summaryData,可能存在也可能不存在,而尝试获取addressLine1是它无法处理的null,导致错误:

System.NullReferenceException发生,Message=Object reference not set to an instance of an object.

以下是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;
        }
    }

如果子树不存在,我不明白为什么会失败,希望能得到任何帮助。


1
您传递的是c.Element("summaryData").Element("serviceAddress").Element("addressLine1"),这个null可能来自于任何一个中间元素缺失。您方法中的null检查只针对最后一个元素进行了检查(实际上被传递到方法中的元素)。 - Colin Mackay
你的示例 XML 无效 - address 标签 - 是打字错误还是实际记录? - Kami
你说得对,我删掉太多了,把结尾的地址标签也删掉了。是笔误。 - user1644147
3个回答

2

汇总数据可能存在,也可能不存在

这就是为什么。因为你嵌套调用,所以你必须对它们进行空值检查全部

这些中的任何一个都可能为空:

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元素传递给扩展方法,如果它不为空,那么就在扩展方法中查找addressLine1,但不确定这是否更清晰。 - user1644147
@user1644147 你可以这样做,代码会更简洁,但是那种方法只对summaryData元素有用,不够通用。最好像上面那样保持不变 :) - Mathew Thompson

1
如果summaryDate元素不存在,则
c.Element("summaryData").Element("serviceAddress").Element("addressLine1")

如果您尝试在空引用(c.Element("summaryData"))上调用Element(),将会抛出NullReferenceException异常。


1
正如之前所述,您的异常是因为您传递了多个嵌套查询。
c.Element("summaryData").Element("serviceAddress").Element("addressLine1")

是写作以下代码的等价形式:

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

如果 c , x1 或 x2 为空,则会出现 NullReferenceException
使用多个空值检查的纯 LINQ 解决方案的一个可能的替代方法是使用 XPath 构建表达式。
使用 XPath ,而不是在每个级别进行空值检查,您可以编写表达式:
street_address = GetElementValue(c.XPathSelectElement("/summaryData/serviceAddress/addressLine1"))

这将评估整个表达式,如果它不存在于其完整性中,则将返回null,但不会像纯LINQ查询一样抛出异常。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接