เหตุใดการเพิ่ม Nullable <int> จึงไม่ทำให้เกิดข้อยกเว้น


99

คุณช่วยอธิบายได้ไหมทำไม Console.WriteLine เขียนบรรทัดว่าง ( Console.WriteLine(null)ให้ข้อผิดพลาดในการคอมไพล์) และทำไมไม่มี NullReferenceException ( a+=1ไม่ควรเพิ่ม)

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

ทั้งหมดของผู้ประกอบการสาม++, +=และ+สายพันธุ์ได้ยก ดังนั้นงบa++;, a += 1;และa = a + 1;ได้รับอนุญาตทั้งหมด แต่ละผลิตnull(ไม่มีข้อยกเว้นโยน) ถ้าเป็นครั้งแรกa null
Jeppe Stig Nielsen

5
NullReferenceExceptionเหรอ? แต่int?ไม่ได้เป็นReferenceก็เป็นเพียงintที่สามารถใช้nullค่า
Khaled.K

คำตอบ:


124

คุณสังเกตผลกระทบจากการที่ผู้ประกอบการยก

จากส่วน 7.3.7 ของข้อกำหนด C # 5:

ตัวดำเนินการที่ยกขึ้นอนุญาตให้ตัวดำเนินการที่กำหนดไว้ล่วงหน้าและผู้ใช้กำหนดซึ่งดำเนินการกับชนิดค่าที่ไม่เป็นค่าว่างสามารถใช้กับรูปแบบที่เป็นโมฆะได้ ตัวดำเนินการแบบยกสร้างขึ้นจากตัวดำเนินการที่กำหนดไว้ล่วงหน้าและผู้ใช้กำหนดซึ่งตรงตามข้อกำหนดบางประการดังที่อธิบายไว้ในต่อไปนี้:

  • สำหรับตัวดำเนินการยูนารีจะ+ ++ - -- ! ~ มีรูปแบบที่ยกขึ้นของตัวดำเนินการหากตัวถูกดำเนินการและชนิดผลลัพธ์เป็นชนิดค่าที่ไม่เป็นค่าว่างได้ แบบฟอร์มที่ยกขึ้นถูกสร้างขึ้นโดยการเพิ่ม?ตัวปรับแต่งเดียวให้กับตัวถูกดำเนินการและชนิดผลลัพธ์ ตัวดำเนินการที่ยกขึ้นจะสร้างค่าว่างถ้าตัวถูกดำเนินการเป็นโมฆะ มิฉะนั้นตัวดำเนินการที่ยกขึ้นจะแกะตัวถูกดำเนินการใช้ตัวดำเนินการที่อยู่ข้างใต้และสรุปผลลัพธ์

โดยพื้นฐานแล้วa++ในกรณีนี้คือนิพจน์ที่มีผลลัพธ์nullเป็น (as an int?) และตัวแปรจะไม่ถูกแตะต้อง

เมื่อคุณโทร

Console.WriteLine(a);

ที่อยู่ในกล่องobjectซึ่งจะแปลงเป็นการอ้างอิงว่างซึ่งพิมพ์เป็นบรรทัดว่าง


3
มีวิธีพิมพ์ "null" โดยไม่ใช้Console.WriteLine(a == null ? "null" : a)หรือไม่?
Cole Johnson

5
@ โคลจอห์นสัน: Console.WriteLine (a ?? "null"); :)
David Chappelle

2
@DavidChappelle เมื่อaเป็นประเภทint?ฉันจะบอกa ?? "null"ว่าไม่พบประเภททั่วไปสำหรับตัวถูกดำเนินการทั้งสอง คุณต้องการคำใบ้ที่objectเป็นประเภททั่วไป ดังนั้นโยนตัวถูกดำเนินการไปที่ aจะได้รับการบรรจุอยู่ในกล่อง ตัวอย่างเช่น((object)a) ?? "null"หรือa ?? (object)"null".
Jeppe Stig Nielsen

สุดยอด. คุณสามารถเชื่อมโยงไปยังสเป็ค? เราจะกำหนดสิ่งนี้ได้ไหมเมื่อเราโอเวอร์โหลดตัวดำเนินการในคลาสของเราเอง
ฟิล

@teabaggs: ฉันไม่สามารถเชื่อมโยงได้อย่างง่ายดายในตอนนี้และลิงก์จะไปยังเอกสาร Word (ซึ่งคุณสามารถค้นหาได้ง่ายพอด้วยการค้นหา) คุณจะได้รับตัวดำเนินการยกโดยอัตโนมัติเมื่อคุณกำหนดตัวดำเนินการเกินพิกัดตามความเหมาะสม
Jon Skeet

116

คำตอบของจอนนั้นถูกต้อง แต่ฉันจะเพิ่มหมายเหตุเพิ่มเติม

เหตุใดจึงConsole.WriteLine(null)ให้ข้อผิดพลาดในการคอมไพล์

มี 19 ทับถมของมีConsole.WriteLineและสามของพวกเขามีผลบังคับใช้กับnull: หนึ่งที่ใช้stringอย่างใดอย่างหนึ่งที่ใช้และหนึ่งที่ใช้เวลาchar[] objectC # ไม่สามารถระบุได้ว่าคุณหมายถึงอะไรในสามคนนี้จึงทำให้เกิดข้อผิดพลาด Console.WriteLine((object)null)จะถูกกฎหมายเพราะตอนนี้ชัดเจนแล้ว

ทำไมConsole.WriteLine(a)เขียนบรรทัดว่าง?

aint?เป็นโมฆะ ความละเอียดเกินพิกัดจะเลือกobjectเวอร์ชันของวิธีการดังนั้นจึงint?ถูกจัดกรอบให้เป็นการอ้างอิงแบบ null โดยพื้นฐานแล้วนี่ก็เหมือนกับConsole.WriteLine((object)null)ที่เขียนบรรทัดว่าง

ทำไมไม่มีNullReferenceExceptionการเพิ่มขึ้น?

การอ้างอิงว่างเปล่าที่คุณกังวลอยู่ที่ไหน aเป็นโมฆะint?ซึ่งไม่ใช่ประเภทอ้างอิงที่จะเริ่มต้นด้วย! โปรดจำไว้ว่าประเภทค่าที่เป็นโมฆะคือประเภทค่าไม่ใช่ประเภทการอ้างอิงดังนั้นอย่าคาดหวังว่าประเภทเหล่านี้จะมีความหมายอ้างอิงเว้นแต่จะถูกจัดให้อยู่ในประเภทอ้างอิง ไม่มีมวยในการต่อเติม


0

คุณเพิ่มค่าว่างหรือไม่ ???

int? a = null;
a++;

คำสั่งนี้หมายถึงnull++คือ null + 1

ตามเอกสารนี้ประเภทที่เป็นโมฆะสามารถแสดงช่วงของค่าที่ถูกต้องสำหรับชนิดค่าพื้นฐานบวกค่าว่างเพิ่มเติม Nullable ออกเสียงว่า "Nullable of Int32" สามารถกำหนดค่าใดก็ได้ตั้งแต่ -2147483648 ถึง 2147483647 หรือ สามารถกำหนดค่า null ได้

ที่นี่คุณกำลังเพิ่มค่า null จากนั้นมันจะกลายเป็นค่าว่างไม่ใช่ 0 หรือจำนวนเต็มอื่น ๆ

ทำไมพิมพ์ว่างแทนที่จะเป็นข้อผิดพลาด ??

เมื่อคุณพิมพ์ประเภท nullable ด้วยค่า null มันจะพิมพ์ว่างแทนข้อผิดพลาดเนื่องจากคุณกำลังพิมพ์ค่าตัวแปร ie ของตำแหน่งหน่วยความจำ ซึ่งอาจเป็นค่าว่างหรือจำนวนเต็มก็ได้

แต่เมื่อคุณพยายามพิมพ์ null โดยใช้Console.WriteLine(null)ค่า null ไม่ใช่ตัวแปรดังนั้นจึงไม่อ้างถึงตำแหน่งหน่วยความจำใด ๆ "NullReferenceException"และด้วยเหตุนี้มันจะช่วยให้เกิดข้อผิดพลาด

แล้วคุณจะพิมพ์จำนวนเต็มโดยใช้อย่างไรConsole.WriteLine(2);??

ในกรณีนี้ 2 จะอยู่ในหน่วยความจำที่ตำแหน่งชั่วคราวและตัวชี้จะชี้ไปที่ตำแหน่งหน่วยความจำที่จะพิมพ์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.