你如何防范Linq To Xml中的空引用异常?

时间:2009-04-27 10:04:28

标签: xml linq exception-handling linq-to-xml

<?xml version="1.0" encoding="utf-8" ?>
<pages> 
  <page id="56">
    <img id="teaser" src="img/teaser_company.png"></img>
  </page>  
</pages>

我有一个xml文件,它为cms中的页面定义了额外的资源。使用LinqToXml查询此文件时,保护Null Reference异常的最佳方法是什么?

var page = (from tabElement in extensionsDoc.Descendants("page")
where tabElement.Attribute("id").Value == tabId.ToString()
select tabElement).SingleOrDefault();

如果页面元素没有名为“id”的属性,则此代码可能会触发Null Reference异常。我是否必须使用try catch块或有办法处理这个问题?例如,如果页面元素没有名为“id”的属性,则为页面对象返回null。

5 个答案:

答案 0 :(得分:28)

编辑:这是很久以前写的 - 这些天我肯定会按照伊戈尔的答案去演员。

最简单的方法是:

var page = (from tabElement in extensionsDoc.Descendants("page")
            let idAttribute = tabElement.Attribute("id")
            where idAttribute != null 
                  && idAttribute.Value == tabId.ToString()
            select tabElement).SingleOrDefault();

或者,您可以将扩展方法写入XElement

public static string AttributeValueOrDefault(this XElement element,
                                             string attributeName)
{
    XAttribute attr = element.Attribute(attributeName);
    return attr == null ? null : attr.Value;
}

然后使用:

var page = (from element in extensionsDoc.Descendants("page")
            where element.AttributeValueOrDefault("id") == tabId.ToString()
            select element).SingleOrDefault();

或使用点符号:

var page = extensionsDoc.Descendants("page")
             .Where(x => x.AttributeValueOrDefault("id") == tabId.ToString())
             .SingleOrDefault();

(事先调用tabId.ToString(),btw,而不是每次迭代都是有意义的。)

答案 1 :(得分:10)

在.NET 4中,LINQ to XML提供了一种方法,它使用explicit casts

var page = (
  from tabElement in extensionsDoc.Descendants("page")
    where (string)tabElement.Attribute("id") == tabId.ToString()
    select tabElement
).SingleOrDefault();

如果属性不存在,则结果将为空。

除了显式string运算符之外,还有大多数基本类型及其Nullable版本。这意味着您可以使用以下语法执行AttributeOrDefault

//<element theAttr="12" />
int theAttr = (int?)doc.Element("element").Attribute("missingAttr") ?? 0;

答案 2 :(得分:3)

我以前见过其他人也使用直接演员来演奏弦乐;我不知道它的效率是否比Jon建议的更高或更低,但我非常喜欢语法。

var page = extensionsDoc.Descendants("page")
             .Where(x => (string)x.Attribute("id") == tabId.ToString())
             .SingleOrDefault();

如果我的思想存在一些缺陷,任何人都可以随意解决这个问题。我对LINQ很新。

答案 3 :(得分:1)

我倾向于使用XPath表达式,否则代码会被大量的空检查混乱。以你的例子:

var query = string.Format("page[@id='{0}']", tabId.ToString());
var page = extensionsDoc.XPathSelectElement(query);

答案 4 :(得分:0)

我会使用一个映射XML元素的类实体。并调用一个检查null值的方法。我在我的代码中使用此方法,它工作正常。希望它有所帮助。

以下是根据您的需求进行调整的示例代码:

private void Method1(...) {
    ...

    var pages = from tabElement in extensionsDoc.Descendants("page")
    where tabElement.Attribute("id").Value == tabId.ToString()
    select new Page {
                imgSrc = Method2(tabElement)
            };

    // pages variable is a List<Page> object
    ...
}

private void Method2(XElement element) {
    XElement img = element.Element("img");

    if (img != null) {
        ...
        // TODO return the imgSrc
        return "";
    }

    // return null or ""
    return null;
}

然后是Page类定义:

class Page
{
    public string imgSrc { get; set; }
}