2009-04-27 4 views
12
<?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?Как вы защищаете исключения Null Reference в Linq To Xml?

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

+0

Как о проверке заранее в табетический? –

ответ

28

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

+0

Метод расширения будет работать только в том случае, если вам не требуется свойство атрибута, например его длина. 'x.AttributeValueOrDefault (" id "). Длина> 0', например, все равно вызовет исключение NullReferenceException. Я думаю, что использование 'let' является более безопасным. _BTW, к сожалению, ReSharper не предупреждает о возможном NullReferenceEception, если вы используете 'let' _ и не проверяете for_' null'. – comecme

+0

@comecme: В этом случае вы можете использовать оператор с нулевым коалесцированием. Это не предназначалось для панацеи ... хотя использование явного приведения на самом деле было бы лучше здесь. –

3

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

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

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

1

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

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

В .NET 4 LINQ к 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

В вашем последнем примере может возникнуть исключение NullReferenceException, если элемент Element '' '' существует. – comecme

0

Я хотел бы использовать класс сущности, отображающую элемент X. И вызовите метод, который будет проверять значение 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; } 
} 
+0

Если 'tabElement' не имеет атрибута' 'id '', это все равно вызовет исключение NullReferenceException в вашем 'Method1'. – comecme

Смежные вопросы