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


98

Console.WriteLineが空の行を書き込む(Console.WriteLine(null)コンパイルエラーが発生する)理由、およびNullReferenceExceptionが発生しない(それa+=1を発生させるべきではない)理由を説明してください。

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

3つの演算子のすべて+++=および+バリアントを引き上げてきました。したがって文がa++;a += 1;、およびa = a + 1;すべて許可されています。最初にのnull場合、それぞれが生成します(例外はスローされません)。anull
Jeppe Stig Nielsen

5
NullReferenceException?しかし、それは価値があるものでint?はありませんReferenceintnull
Khaled.K '25

回答:


124

リフトオペレーターの影響を観察しています。

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

リフトされた演算子により、null可能ではない値の型を操作する事前定義およびユーザー定義の演算子を、それらの型のnull可能形式で使用することができます。リフトオペレーターは、以下で説明するように、特定の要件を満たす事前定義およびユーザー定義のオペレーターから構成されます。

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

したがって、基本的にa++、この場合の結果はnull(としてint?)の式であり、変数は変更されません。

あなたが電話するとき

Console.WriteLine(a);

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


3
を使用せずに「null」を印刷する方法はありConsole.WriteLine(a == null ? "null" : a)ますか?
Cole Johnson、

5
@Cole Johnson:Console.WriteLine(a ?? "null"); :)
デビッドシャペル2015年

2
@DavidChappelleときaタイプのものでありint?、私が言ってないだろうa ?? "null"な発見に二つのオペランドのための一般的なタイプを。object一般的なタイプのヒントが必要です。したがって、どちらかのオペランドをそれにキャストします。a箱詰めされます。たとえば((object)a) ?? "null"またはa ?? (object)"null"
Jeppe Stig Nielsen

素晴らしい。スペックにリンクできますか?独自のクラスで演算子をオーバーロードするときにこれを定義できますか?
Phil

@teabaggs:現在、簡単にリンクすることはできません。リンクは、Wordドキュメント(検索で簡単に見つけることができます)へのリンクになります。必要に応じて、演算子のオーバーロードを定義すると、演算子が自動的に解除されます。
Jon Skeet

116

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

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

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

なぜConsole.WriteLine(a)空の行を書くのですか?

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

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

あなたが心配しているnull 参照はどこにありますか? そもそも参照型ではないanull int?です!null許容値型は値型であり、参照型ではないので、参照型にボックス化されていない限り、それらが参照セマンティクスを持つことを期待しないでください。追加でボクシングはありません。


0

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

int? a = null;
a++;

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

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

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

エラーの代わりに空白が印刷されるのはなぜですか?

null値を含むnull許容型を出力すると、変数(メモリ位置の値)を出力するため、エラーではなく空白が出力されます。nullまたは任意の整数。

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

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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.