C#のささやかな(でもかっこいい)言語機能の1つが??です。"Null合体"演算子です。これにより、値がNullかどうかをチェック、また、もしそうであれば代替値を返すという、きれいで簡潔な方法が提供されます。
簡単な使用例
過去に何人かの方がすでに??演算子についてブログを書かれています。使用方法については、いくつか以前に例を ここ、ここ、ここ、ここ にあげていますのでお読み頂ければと思います。単純に言うと、??演算子は式の左側で提供されている値がNullであるかどうか、もしそうであれば式の右側に表示されている代替値を返すというチェックを行います。もし式の左側の値がNullでない場合、元の値を返します。
例えば、仮に"message"という文字列変数があるとします。messageがNullかどうかをチェックし、代替値を以下のコードを使用して返すことができます。:
上記の"message"変数はNullではなかったので、"result"変数には元の"hello world"というmessageの値が割り当てられています。
以下のスニペットでは、反対にmessageがNull値なので、??演算子は代替にある値を返します。:
??演算子は参照型と値型の両方で動作します。例えば、以下はNullableのinteger型の"number"変数がNullかどうかをチェックしています。変数はNullではないので、結果は元の値(55)になります。:
"number"がNullだった場合、結果は0値が割り当てられます。:
LINQで??演算子を使用
先月、.NET 3.5で新しくサポートされているLINQ to XMLを使用でカバーしたブログ投稿を行っています。"ガッチャ"の1つで、よくXML形状が非形式だったり要素および属性が欠けていたりしたケースで生のXMLを処理する場合に必要になります。??演算子はそういったシナリオで非常に有用です。
例えば、次のような連絡先データのXMLファイルを持っている、またはフィードする場合で考えてみましょう。:
C#で以下のようなLINQ to XMLコードを書いて、XMLファイルを開き、"Name"、"Title"、"Email"、"YearsAtCompany"プロパティを持つ一連の匿名型オブジェクトを取得して、ページ上の<asp:gridview>コントロールに結果をデータバインドすることができます。:
上記でXElementクラス上で明示的な変換演算子サポートをどのように使用して、XMLから強く型付けされた値を取得しているかお分かり頂けると思います。これによりc.Element("YearsAtCompany")値をintにキャストするだけでよくなります。そうすれば、自動的に文字列変数はintegerに変換され、匿名型上の"YearsAtCompany"プロパティはint型に変換されます。
上記のコードスニペットを起動した時、連絡先一覧を表示したきれいなGridviewが表示されます。:
この明示的な変換サポートは<YearsAtCompany>要素が常に定義されている場合には非常に上手く動作します。しかし<Contact>で<YearsAtCompany>サブ要素が欠けている場合はランタイムエラーが発生します。:
これを修正する方法としては、LINQ to XMLクエリを修正します。それによりYearsAtCompanyがNullableのInteger型であることを示すことができます。これは明示的キャストを(int)を(int?)に変換することで行うことができます。:
これにより、クエリをクリーンに実行し、エラーの発生を抑えることができるようになります。<YearsAtCompany>要素がXMLに無い場合は、代わりにNull値をYearsAtCompanyプロパティに割り当てます。
アプリケーションを実行してGridviewに結果をデータバインドした時、3つ目の連絡先のYearsAtCompany列には結果として空(値がNullなため)になっていることがご覧頂けます。:
しかし、XMLで欠けている値をNull値に変換せずに、単に0の値を表示したい場合はどうすればいいでしょうか?
その場合に、この??演算子サポートを利用します。LINQ to XMLクエリを以下の様に修正するだけで、要素が無い場合にデフォルト値を0として表示することができます。:
これは、<YearsAtCompany>要素がXMLに無いと、結果がNullとなる場合に、代わりに0が割り当てられるということを示しています。上記のインテリセンスを見て頂くと、C#は自動的にそれを検知しています。つまり、新しい匿名型上のYearsAtCompanyプロパティは絶対にNullにはならないことを意味しています。そのため、プロパティが(int?)の代わりに(int)型でマークされています。
ページを起動すると3行目には空の値の代わりに0が表示されます。:
まとめ
どんなシナリオにおいてもC#の??演算子を使用することができます。上記のLINQ to XMLシナリオにより、その他のLINQシナリオ(LINQ to SQL、LINQ to XML、LINQ to Object、LINQ to SharePointなど)での使用方法におけるヒントとしてご利用頂ければ幸いです。
Hope this helps,
Scott