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> 

私は、CMS内のページの追加リソースを定義するxmlファイルを持っています。 LinqToXmlでこのファイルを照会するときにNull参照の例外を防ぐ最善の方法は何ですか?ページ要素は、「ID」と呼ばれる属性を持っていない場合Linq To XmlのNull参照例外をどうやって保護しますか?

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

このコードは、潜在的にnull参照の例外を引き起こす可能性があります。 try catchブロックを使用する必要がありますか、これを処理する方法はありますか?たとえば、ページ要素に "id"という属性がない場合は、ページオブジェクトをページするためにnullを返します。

+0

どのように? –

答えて

28

EDIT:これは長い時間前にはっきりと書かれていましたが、最近ではイゴールの答えに従ってキャストしています。

最も簡単な方法は、のようになります。また、あなたがXElementに拡張メソッドを書くことができ

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

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 ").Length> 0'の場合でもNullReferenceExceptionがスローされます。私は 'let'を使う方が安全だと思います。 _BTW、残念ながらReSharperはあなたが 'let'を使用し、' null 'をチェックしないと、NullReferenceEceptionについて警告しません。 – comecme

+0

@comecme:この場合、ヌル合体演算子を使用できます。それは万能薬になることを意図していませんでした...明示的なキャストを使用することは実際にはここでより良いでしょう。 –

3

私は他の人が同様に前に文字列にまっすぐにキャストを使用し見てきました。 Jonが提案したものより多かれ少なかれ効率的かどうかはわかりませんが、私は構文がとても好きです。

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

誰でも修正すること自由に感じている私の考えでは、いくつかの欠陥があるかどう;私はLINQにとってかなり新しいです。

1

私はXPath式を使用する傾向があります。ここでは、多くのヌルチェックでコードが煩雑になります。あなたの例:XMLへの.NET 4 LINQでは

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

はそれを行うための方法を提供し、それがexplicit castsを使用している:

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

属性が存在しない場合、結果は単純になりますnullになります。

明示的なstring演算子に加えて、ほとんどのプリミティブ型とNullableバージョンもあります。これは、構文のこの種を使用してAttributeOrDefaultを行うことができますことを意味します

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

あなたの最後の例は、Element要素が存在しない場合、NullReferenceExceptionの場合があります。 – comecme

0

私は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クラスの定義:tabId先行チェックについて

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

'tabElement'に属性" id "がない場合、それは引き続き' Method1'にNullReferenceExceptionを引き起こします。 – comecme

関連する問題