Как вы защищаете исключения 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".
Ответы
Ответ 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; }
}