更新: Visual Studio 2015以降、C#コンパイラー(言語バージョン6)が?.
演算子を認識するようになり、 "ディープnullチェック"が簡単になりました。詳細については、この回答を参照してください。
コードを再設計することとは別に、
この削除された回答が示唆するように、別の(ひどいですが)オプションは、try…catch
ブロックを使用して、NullReferenceException
その深いプロパティルックアップ中にいつか発生するかどうかを確認することです。
try
{
var x = cake.frosting.berries.loader;
...
}
catch (NullReferenceException ex)
{
// either one of cake, frosting, or berries was null
...
}
私は個人的には次の理由でこれをしません:
- 見た目が良くない。
- 例外処理を使用します。例外処理は、例外的な状況を対象とするものであり、通常の操作中に頻繁に発生するものではありません。
NullReferenceException
sはおそらく明示的に捕捉されるべきではありません。(この質問を参照してください。)
だからいくつかの拡張メソッドを使用することは可能ですか、それとも言語機能でしょうか、[...]
これは、C#でより高度な遅延評価が行われていない限り、またはリフレクションを使用したい場合(おそらくこれもおそらくない)でない限り、ほぼ間違いなく言語機能(.?
and ?[]
演算子の形式でC#6で利用可能)でなければなりません。パフォーマンスとタイプセーフの理由から良い考えです)。
cake.frosting.berries.loader
関数に単純に渡す方法がないため(評価されてnull参照例外がスローされます)、次の方法で一般的なルックアップメソッドを実装する必要があります。調べる:
static object LookupProperty( object startingPoint, params string[] lookupChain )
{
// 1. if 'startingPoint' is null, return null, or throw an exception.
// 2. recursively look up one property/field after the other from 'lookupChain',
// using reflection.
// 3. if one lookup is not possible, return null, or throw an exception.
// 3. return the last property/field's value.
}
...
var x = LookupProperty( cake, "frosting", "berries", "loader" );
(注:コードは編集されています。)
このようなアプローチにはいくつかの問題があります。まず、単純な型のプロパティ値の型の安全性とボックス化の可能性はありません。次に、null
何か問題が発生した場合に戻ることができ、呼び出し側の関数でこれを確認する必要があります。または、例外をスローして、開始した場所に戻ります。第三に、それは遅いかもしれません。第四に、それはあなたが始めたものより醜く見えます。
[...]、またはそれは単に悪い考えですか?
私はどちらかにとどまります:
if (cake != null && cake.frosting != null && ...) ...
または、Mehrdad Afshariによる上記の回答を使用してください。
PS:私がこの回答を書いたとき、ラムダ関数の式ツリーは考慮していませんでした。この方向での解決策については、たとえば@driisの回答を参照してください。また、一種のリフレクションに基づいているため、より単純なソリューション(if (… != null & … != null) …
)ほどうまく機能しない可能性がありますが、構文の観点からはより適切に判断できます。