web-dev-qa-db-ja.com

Nullable <int>をインクリメントしても例外がスローされないのはなぜですか?

Console.WriteLineが空の行を書き込む(Console.WriteLine(null)がコンパイルエラーを発生させる)理由と、NullReferenceExceptionが発生しない理由(a+=1でさえ発生させない理由)を教えてください。

int? a = null;
a++; // Why there is not NullReferenceException? 
Console.WriteLine(a); // Empty line
97
FSou1

lifted operatorの効果を観察しています。

C#5仕様のセクション7.3.7から:

リフト演算子を使用すると、nullを許可しない値型を操作する事前定義およびユーザー定義の演算子を、それらの型のnullを許可する形式でも使用できます。リフト演算子は、以下で説明するように、特定の要件を満たす定義済みおよびユーザー定義の演算子から構築されます。

  • 単項演算子の場合+ ++ - -- ! ~オペランドと結果の型が両方ともnullを許可しない値型である場合、リフトされた形式の演算子が存在します。リフトされたフォームは、単一の?オペランドと結果の型の修飾子。オペランドがヌルの場合、リフト演算子はヌル値を生成します。それ以外の場合、リフトされた演算子はオペランドをアンラップし、基礎となる演算子を適用して、結果をラップします。

だから基本的に、 a++この場合の結果は、nullint?)変数はそのままです。

電話するとき

Console.WriteLine(a);

それはobjectにボックス化され、それを空の行として出力されるnull参照に変換します。

121
Jon Skeet

Jonの答えは正しいですが、いくつか追加のメモを追加します。

Console.WriteLine(null)がコンパイルエラーを出すのはなぜですか?

_Console.WriteLine_には19のオーバーロードがあり、そのうち3つはnullに適用できます:stringを取るもの、_char[]_を取るもの、 objectを取ります。 C#では、これら3つのうちどれを意味するかを判断できないため、エラーが発生します。 Console.WriteLine((object)null)は明確になったので合法です。

Console.WriteLine(a)が空の行を書き込むのはなぜですか?

aはnull _int?_です。オーバーロード解決は、メソッドのobjectバージョンを選択するため、_int?_はnull参照にボックス化されます。したがって、これは基本的に空行を書き込むConsole.WriteLine((object)null)と同じです。

増分にNullReferenceExceptionがないのはなぜですか?

あなたが心配しているnull 参照はどこですか? aはnull _int?_であり、最初は参照型ではありません!ヌル可能な値タイプは値タイプではなく参照タイプであるため、参照タイプにボックス化されない限り、参照セマンティクスを持つことを期待しないでください。さらに、ボクシングはありません。

115
Eric Lippert

Nullをインクリメントしていますか?

_int? a = null;
a++;
_

このステートメントは、単に_null++_、つまりnull + 1を意味します。

このドキュメントによると、nullable型は、基になる値型の値の正しい範囲に加えて、追加のnull値を表すことができます。 null値を割り当てることができます

ここでは、nullをインクリメントしています。また、0やその他の整数ではなくnull値になります。

エラーではなく空白で印刷されるのはなぜですか??

null値を持つnull許容型を印刷すると、変数、つまりメモリ位置の値を印刷しているため、エラーではなく空白が印刷されます。 nullまたは任意の整数。

ただし、Console.WriteLine(null)を使用してnullを出力しようとすると、nullは変数ではないため、メモリの場所を参照しません。したがって、エラー_"NullReferenceException"_が発生します。

次に、Console.WriteLine(2);を使用してどのように整数を印刷できますか??

この場合、2は一時的な場所でメモリに格納され、ポインタは印刷するメモリの場所を指します。

0
Laxmikant Dange