Как вы защищаете исключения Null Reference в Linq To Xml? - PullRequest
12 голосов
/ 27 апреля 2009
<?xml version="1.0" encoding="utf-8" ?>
<pages> 
  <page id="56">
    <img id="teaser" src="img/teaser_company.png"></img>
  </page>  
</pages>

У меня есть XML-файл, который определяет дополнительные ресурсы для страниц в cms. Каков наилучший способ защиты от исключений Null Reference при запросе этого файла с помощью LinqToXml?

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

Этот код может вызвать исключение Null Reference, если элемент страницы не имеет атрибута с именем "id". Нужно ли использовать блок try catch или есть способ справиться с этим? Например, верните null для страницы объекта страницы, если для элемента страницы нет атрибута с именем "id".

Ответы [ 5 ]

28 голосов
/ 27 апреля 2009

РЕДАКТИРОВАТЬ: Это было ясно написано давным-давно - в эти дни я определенно пошел бы с актерами согласно ответу Игоря.

Самый простой способ будет выглядеть примерно так:

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() один раз заранее, кстати, а не для каждой итерации.)

10 голосов
/ 25 января 2011

В .NET 4 LINQ to XML предоставляет способ сделать это, используя явное приведение :

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;
3 голосов
/ 23 июля 2009

Я уже видел, как другие люди использовали прямое приведение к строке; Я не знаю, является ли это более или менее эффективным, чем то, что предложил Джон, но мне очень нравится синтаксис.

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

Кто-нибудь может это исправить, если в моем мышлении есть какой-то недостаток; Я совершенно новичок в LINQ.

1 голос
/ 10 декабря 2010

Я склонен использовать выражения XPath, где в противном случае код был бы загроможден множеством пустых проверок. Для вашего примера:

var query = string.Format("page[@id='{0}']", tabId.ToString());
var page = extensionsDoc.XPathSelectElement(query);
0 голосов
/ 28 декабря 2011

Я бы использовал сущность класса, отображающую элемент XML. И вызвать метод, который будет проверять нулевое значение. Я использую этот метод в своем коде, он отлично работает. Надеюсь, это поможет.

Вот пример кода для настройки в зависимости от ваших потребностей:

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; }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...