如何使用linq2Xml没有null异常的可能性?

时间:2009-11-15 17:06:25

标签: c# linq-to-xml

我编写了这个简单的linq-to-xml查询,似乎使用linq语法无法避免null异常。我用错了吗?什么应该是正确的(和简短的)Linq2Xml语法?

linq2Xml查询

var userData =
    queryUserResponseData.Elements("user")
        .Single(u => u.Element("username").Value == userName);

XML

<data>
    <user>
        <username>User1</username>
        <userid>123</userid>
    </user>
    <user>
        <username>User2</username>
        <userid>456</userid>
    </user>
    <user>
        <userid>999</userid>
    </user>
</data>

5 个答案:

答案 0 :(得分:5)

XElement和XAttribute有一些显式转换运算符,可将其值转换为特定类型。它们非常有用,因为当元素或属性丢失时返回null。

var userData = queryUserResponseData.Elements("user").Single(u => (string)u.Element("username") == userName);

答案 1 :(得分:2)

从你对Ahmad Mageed的回答的评论:

  

问题实际上是u.Element("username").Value,其中Resharper通知我可能的空异常

听起来你可能会担心潜在而不是真正的问题。您知道您的数据将意味着您将始终返回1个结果,但是ReSharper无法访问您的数据,因此它突出显示如果没有结果则会生成空引用异常。

你可以做以下三件事之一:

  1. 忽略警告并且什么都不做。

  2. 重新编码以解决此问题,以便不会出现异常(请参阅其他答案)。

  3. 将Linq包裹在try {} catch {}中,这样如果“不可想象”发生,您的程序就不会崩溃。

  4. 只有你能真正决定你想做什么。

答案 2 :(得分:1)

使用Single表示您预计会有1个结果。返回更多结果时,Single将抛出异常。您可以使用First获取第一个项目,或使用Last获取最后一个项目。对于多个项目,您需要遍历结果并单独访问每个项目。

如果不存在匹配结果,您可以使用SingleOrDefault返回null值或所用类型的默认值。

queryUserResponseData是XElement还是XDocument?如果它是XDocument,则需要首先访问XML的根目录,例如:

var userData = queryUserResponseData.Root.Elements("user")
                 .Single(u => u.Element("username").Value == userName);

除此之外,在样本中搜索User1或User2也行。但是,如果您搜索不存在的 User3 ,则Single会抛出异常。在这种情况下,您应该使用SingleOrDefault:

var userData = queryUserResponseData.Elements("user")
                 .SingleOrDefault(u => u.Element("username").Value == "User3");

答案 3 :(得分:1)

根据您对Ahmad的回答的评论,我假设当元素没有节点时你会得到NullReferenceException。您可以像这样修复它 -

var userData =
    doc.Elements("user")
    .Single(u => u.Element("username") != null && u.Element("username").Value == userName);

但是如果DTD或XSD需要用户名节点,或者您确定所有元素都有用户名节点,则可以忽略ReSharper警告。

答案 4 :(得分:0)

var userData = queryUserResponseData.Elements("user")
    .Select(u => u.Element("username"))
    .Where(uNode => uNode != null)
    .Single(uName => uName.Value == userName);