Mengapa menambahkan Nullable <int> tidak memunculkan pengecualian?

98

Bisakah Anda menjelaskan, mengapa Console.WriteLine menulis baris kosong ( Console.WriteLine(null)beri saya kesalahan kompilasi) dan mengapa tidak ada NullReferenceException (bahkan a+=1tidak boleh menaikkannya)?

int? a = null;
a++; // Why there is not NullReferenceException? 
Console.WriteLine(a); // Empty line
Maxim Zhukov
sumber
Semua dari tiga operator ++, +=dan +telah mengangkat varian. Oleh karena itu laporan a++;, a += 1;dan a = a + 1;semua diperbolehkan. Setiap produk null(tidak terkecuali dibuang) jika aawalnya null.
Jeppe Stig Nielsen
5
NullReferenceException? tetapi int?bukan Reference, itu hanya intyang dapat mengambil nullnilai
Khaled.K

Jawaban:

124

Anda sedang mengamati efek dari operator yang diangkat .

Dari bagian 7.3.7 spesifikasi C # 5:

Operator yang diangkat mengizinkan operator yang ditentukan sebelumnya dan yang ditentukan pengguna yang beroperasi pada tipe nilai non-nullable juga digunakan dengan bentuk nullable dari tipe tersebut. Operator yang diangkat dibuat dari operator yang ditentukan sebelumnya dan yang ditentukan pengguna yang memenuhi persyaratan tertentu, seperti yang dijelaskan berikut ini:

  • Untuk operator unary, + ++ - -- ! ~ bentuk operator yang diangkat ada jika jenis operan dan hasil keduanya merupakan jenis nilai yang tidak dapat dinolkan. Bentuk yang diangkat dibuat dengan menambahkan ?pengubah tunggal ke jenis operan dan hasil. Operator yang diangkat menghasilkan nilai null jika operannya null. Jika tidak, operator yang diangkat membuka bungkus operand, menerapkan operator yang mendasarinya, dan membungkus hasilnya.

Jadi pada dasarnya, a++dalam hal ini adalah ekspresi dengan hasil null(sebagai int?) dan variabel tidak tersentuh.

Saat Anda menelepon

Console.WriteLine(a);

yang dimasukkan ke dalam kotak object, yang mengubahnya menjadi referensi null, yang dicetak sebagai baris kosong.

Jon Skeet
sumber
3
Apakah ada cara untuk mencetak "null" tanpa menggunakan Console.WriteLine(a == null ? "null" : a)?
Cole Johnson
5
@Cole Johnson: Console.WriteLine (?? "null"); :)
David Chappelle
2
@DavidChappelle Kapan aadalah tipe int?, saya akan mengatakan a ?? "null"tidak menemukan tipe umum untuk dua operan. Anda membutuhkan petunjuk yang objectmerupakan tipe umum. Jadi gunakan salah satu operan untuk itu. The aakan kotak. Misalnya ((object)a) ?? "null"atau a ?? (object)"null".
Jeppe Stig Nielsen
super. dapatkah Anda menautkan ke spesifikasi? bisakah kita mendefinisikan ini ketika kita membebani operator di kelas kita sendiri?
Phil
@teabaggs: Saya tidak dapat dengan mudah menautkan saat ini, dan tautannya hanya ke dokumen Word (yang dapat Anda temukan cukup mudah dengan pencarian). Anda secara otomatis mendapatkan operator yang diangkat saat Anda menentukan kelebihan beban operator, jika sesuai.
Jon Skeet
116

Jawaban Jon benar tetapi saya akan menambahkan beberapa catatan tambahan.

Mengapa Console.WriteLine(null)memberikan kesalahan kompilasi?

Ada 19 beban berlebih dari Console.WriteLinedan tiga di antaranya berlaku untuk null: satu yang menerima a string, satu yang mengambil char[]dan satu yang mengambil object. C # tidak dapat menentukan yang mana dari ketiga ini yang Anda maksud, jadi ini memberikan kesalahan. Console.WriteLine((object)null)akan legal karena sekarang sudah jelas.

mengapa Console.WriteLine(a)menulis baris kosong?

aadalah null int?. Resolusi kelebihan beban memilih objectversi metode, sehingga int?dimasukkan kotak ke referensi null. Jadi ini pada dasarnya sama dengan Console.WriteLine((object)null), yang menulis baris kosong.

Mengapa tidak ada NullReferenceExceptionkenaikan?

Di mana referensi nol yang Anda khawatirkan? aadalah null int?yang bukan merupakan tipe referensi untuk memulai! Ingat, tipe nilai nullable adalah tipe nilai , bukan tipe referensi , jadi jangan berharap mereka memiliki semantik referensi kecuali mereka dikotakkan ke tipe referensi. Tidak ada tambahan tinju.

Eric Lippert
sumber
0

Apakah Anda menambahkan null ???

int? a = null;
a++;

Pernyataan ini berarti null++yaitu null + 1.

Sesuai dengan dokumen ini, Jenis nullable dapat mewakili rentang nilai yang benar untuk jenis nilai dasarnya, ditambah nilai null tambahan. Nullable, diucapkan "Nullable of Int32", dapat diberi nilai apa pun dari -2147483648 hingga 2147483647, atau dapat diberi nilai nol

Di sini Anda menambahkan nol, maka itu juga akan menjadi nilai nol bukan 0 atau bilangan bulat lainnya.

Mengapa mencetak kosong, bukan error ??

ketika Anda mencetak tipe nullable dengan nilai null mencetak kosong bukannya kesalahan karena Anda mencetak variabel yaitu nilai lokasi memori. yang mungkin nol atau bilangan bulat apa pun.

Tetapi ketika Anda mencoba untuk mencetak null menggunakan Console.WriteLine(null), karena null bukanlah variabel, jadi tidak merujuk ke lokasi memori apa pun. Dan karena itu memberikan kesalahan "NullReferenceException".

Lalu bagaimana Anda bisa mencetak integer apapun menggunakan Console.WriteLine(2);??

Dalam kasus ini, 2 akan masuk ke memori di lokasi sementara, dan penunjuk menunjuk ke lokasi memori tersebut untuk mencetak.

Laxmikant Dange
sumber