セマンティクスが好きだったので、私は常にNullable<>.HasValue
を使用しました。ただし、最近私は他の誰かの既存のコードベースに取り組んでいて、代わりにNullable<> != null
を排他的に使用していました。
どちらか一方を使用する理由はありますか、それとも純粋に好みですか?
int? a;
if (a.HasValue)
// ...
vs.
int? b;
if (b != null)
// ...
コンパイラーは、null比較をHasValue
の呼び出しに置き換えますので、実際の違いはありません。あなたとあなたの同僚にとって、より読みやすい/より理にかなっている方法を実行してください。
構文が参照型と一致するように(a != null)
を好みます。
さまざまな方法を使用して、null許容intに値を割り当てることで、これについていくつかの調査を行いました。これが私がさまざまなことをしたときに起こったことです。何が起こっているのかを明確にする必要があります。覚えておいてください:Nullable<something>
または短縮形のsomething?
は、nullをクラスであるかのように使用できるようにするためにコンパイラが多くの作業を行っているように見える構造体です。
以下に示すように、SomeNullable == null
とSomeNullable.HasValue
は常に期待されるtrueまたはfalseを返します。以下では説明していませんが、SomeNullable == 3
も有効です(SomeNullableがint?
であると仮定)。null
をSomeNullable
に割り当てた場合、SomeNullable.Value
は実行時エラーになります。実際、これは、オーバーロードされた演算子、オーバーロードされたobject.Equals(obj)
メソッド、およびコンパイラーの最適化とモンキービジネスの組み合わせのおかげで、nullableが問題を引き起こす可能性がある唯一のケースです。
以下に、私が実行したコードの説明と、ラベルで生成された出力を示します。
int? val = null;
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
では、次の初期化方法を試してみましょう。
int? val = new int?();
lbl_Val.Text = val.ToString(); //Produced an empty string.
lbl_ValVal.Text = val.Value.ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValEqNull.Text = (val == null).ToString(); //Produced "True" (without the quotes)
lbl_ValNEqNull.Text = (val != null).ToString(); //Produced "False"
lbl_ValHasVal.Text = val.HasValue.ToString(); //Produced "False"
lbl_NValHasVal.Text = (!(val.HasValue)).ToString(); //Produced "True"
lbl_ValValEqNull.Text = (val.Value == null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
lbl_ValValNEqNull.Text = (val.Value != null).ToString(); //Produced a runtime error. ("Nullable object must have a value.")
前と同じです。 nullを許可するオブジェクトのVALUEはnullを許可しないため、コンストラクタにnullを渡してint? val = new int?(null);
で初期化すると、コンパイル時エラーが発生することに注意してください。 nullに等しくなることができるのはラッパーオブジェクト自体のみです。
同様に、次からコンパイル時エラーが発生します。
int? val = new int?();
val.Value = null;
とにかくval.Value
は読み取り専用プロパティであり、次のようなものさえ使用できないことを意味します:
val.Value = 3;
繰り返しますが、多態性のオーバーロードされた暗黙的な変換演算子を使用すると、次のことができます。
val = 3;
それが正しく機能している限り、何も多めに心配する必要はありませんか? :)
VB.Netで。 「.HasValue」を使用できる場合は、「IsNot Nothing」を使用しないでください。 「IsNot Nothing」を「.HasValue」で一箇所で置き換えることにより、「操作がランタイムを不安定化する可能性がある」中程度の信頼エラーを解決しました。理由はよくわかりませんが、コンパイラで何かが異なって発生しています。 C#の "!= null"にも同じ問題があると思います。
Linqを使用してコードを短くしたい場合は、常に!=null
を使用することをお勧めします
そして、これが理由です:
nullable double変数Foo
を持つクラスSomeDouble
があるとします
public class Foo
{
public double? SomeDouble;
//some other properties
}
コードのどこかで、Fooのコレクションからnull以外のSomeDouble値を持つすべてのFooを取得する場合(コレクション内の一部のfooもnullになる可能性があると仮定)、関数を記述する少なくとも3つの方法になります( C#6を使用:
public IEnumerable<Foo> GetNonNullFoosWithSomeDoubleValues(IEnumerable<Foo> foos)
{
return foos.Where(foo => foo?.SomeDouble != null);
return foos.Where(foo=>foo?.SomeDouble.HasValue); // compile time error
return foos.Where(foo=>foo?.SomeDouble.HasValue == true);
return foos.Where(foo=>foo != null && foo.SomeDouble.HasValue); //if we don't use C#6
}
そして、この種の状況では、私は常に短いものに行くことをお勧めします