Подтвердить что ты не робот

Как вы защищаете исключения Null Reference в 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. Какой лучший способ защитить исключения Null Reference при запросе этого файла с помощью LinqToXml?

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

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

4b9b3361

Ответ 1

EDIT: Это было ясно написано давно - в эти дни я определенно поеду с актерским составом по словам Игоря.

Самый простой способ - это что-то вроде:

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

Ответ 2

В .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

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

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

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

Ответ 4

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

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

Ответ 5

Я бы использовал объект класса, отображающий элемент 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;
}

Затем определение класса страницы:

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