อะไรคือความแตกต่างระหว่างการประกาศคลาส null และการสร้างอินสแตนซ์ของคลาส?

ฉันไม่แน่ใจว่าคำถามของฉันสมเหตุสมผลหรือไม่ แต่ฉันแค่สงสัยว่าโค้ดสองบรรทัดนี้มีความแตกต่างกันหรือไม่:

Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();

vs

Dictionary<int, List<string>> myDictionary = null;

ฉันรู้ว่าบรรทัดแรก instatiates วัตถุพจนานุกรมใหม่ แต่เนื่องจากฉันไม่ได้เพิ่มอะไรลงในพจนานุกรม มันจึงเป็นเพียงวัตถุว่างเปล่า บรรทัดที่สองเป็นเพียงวัตถุพจนานุกรมที่ว่างเปล่า มีความแตกต่างหรือไม่?


person d1du    schedule 11.07.2016    source แหล่งที่มา
comment
คุณสามารถใช้ดีบักเกอร์ของคุณและค้นหาด้วยตัวเอง?!?   -  person Uwe Keim    schedule 11.07.2016
comment
Null ชี้ไปที่ไม่มีวัตถุ ที่นี่เราเห็นข้อมูลและข้อเท็จจริงบางอย่างเกี่ยวกับตัวอักษรที่เป็นโมฆะ (null) Null แสดงด้วยค่า 0 แต่คุณไม่สามารถใช้ 0 แทนค่า null ในโปรแกรมของคุณได้ Null ทำให้เกิดข้อยกเว้นมากมาย   -  person Gehan Fernando    schedule 11.07.2016
comment
ลองโทรไปที่ .Count ทั้ง 2 แห่ง แล้วคุณจะเห็นความแตกต่างในไม่ช้า!   -  person CompuChip    schedule 11.07.2016
comment
อาจซ้ำกันของ อะไรเป็น null ใน Java? หรือ อะไรคือ null ใน c#, java?   -  person Draken    schedule 11.07.2016
comment
ขอขอบคุณทุกการตอบรับที่ไม่ใช่โทรลล์ ผู้ลงคะแนนเสียงต่ำรับ lyfe pl0x   -  person d1du    schedule 08.10.2016


คำตอบ (6)


ในกรณีแรก:

     Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
     myDictionary.Add(key,value); // NOT throw null reference exception.

ในกรณีที่สอง:

     Dictionary<int, List<string>> myDictionary = null;
     myDictionary.Add(key,value); // will throw null reference exception.

หากต้องการใช้วัตถุคอลเลกชัน คุณจะต้องสร้างตัวยึดตำแหน่งก่อน

person Gaurava Agarwal    schedule 11.07.2016
comment
ฉันขอแนะนำให้คุณเปลี่ยนตัวอย่างของคุณเป็นตัวอย่างที่จะคอมไพล์ - และใช้คำศัพท์ C# แทนที่จะเป็นคำศัพท์เฉพาะของ Java (ข้อยกเว้น การอ้างอิง null ไม่ใช่ข้อยกเว้น ตัวชี้ null) - person Jon Skeet; 11.07.2016

ลองคิดดูดังต่อไปนี้:

ตัวแปรเป็นกระดาษเปล่า คุณ อาจ หรือ อาจไม่ เขียนที่อยู่ที่นำคุณไปยังสถานที่บางแห่ง

บรรทัดแรกเขียนบนกระดาษถึงที่อยู่ของวัตถุ (สร้างขึ้นหลังจากคำหลักใหม่)

ในบรรทัดที่สอง คุณเพียงแค่มีกระดาษเปล่าที่คาดหวัง (โดยคอมไพเลอร์) เพื่อเก็บการอ้างอิงพจนานุกรมในบางจุด แต่ปัจจุบันเป็นเพียงกระดาษเปล่า ดังนั้นหากคุณพยายามใช้มันเพื่อไปที่ที่อยู่พจนานุกรม คุณจะทำไม่ได้ (หรือที่เรียกว่า NullReferenceException) ไม่มีข้อมูลเกี่ยวกับตำแหน่งของวัตถุ (ไม่มีที่อยู่จริง)

ในรหัส:

Dictionary<int, List<string>> myDictionary = new Dictionary<int, List<string>>();
myDictionary.Add(1, "1"); // OK, myDictionary points to an address of
                         // Dictionary object and I can access it.

ในขณะที่:

Dictionary<int, List<string>> myDictionary = null;
myDictionary.Add(1, "1");  // Fails at run-time, I have no address for a Dictionary object 
                           // here AKA : NullReferenceException

ข้อความผิดที่คุณกล่าวว่า:

คุณไม่ได้ ประกาศคลาส null อย่างที่คุณพูด คุณกำลังสร้างตัวแปรที่ชี้ไปที่ null

บรรทัดที่สองไม่ใช่ วัตถุพจนานุกรมที่ว่างเปล่า อย่างที่คุณพูด เป็นตัวแปรประเภท Dictionary ที่ชี้ไปที่ NULL ไม่มีวัตถุพจนานุกรมว่างในหน่วยความจำ

person Zein Makki    schedule 11.07.2016

บรรทัดแรกสร้างวัตถุจริง ๆ (จัดสรรหน่วยความจำ) หมายความว่าคุณมีบางสิ่งที่ต้องอ้างอิงและดำเนินการ (เช่น myDictionary.Count() จะส่งกลับ 0) รหัส if (null == myDictionary) จะประเมินเป็น false

บรรทัดที่สองไม่สร้างวัตถุ คุณไม่มีการอ้างอิงถึงอะไรเลย (และในกรณีนี้ การเรียก myDictionary.Count() จะส่งผลให้ NullReferenceException ถูกส่งออกไป) รหัส if (null == myDictionary) จะประเมินเป็น true

person Jacob Pitts    schedule 11.07.2016
comment
ไม่ใช่ว่าคุณจะใช้ Yoda Conditions ใน C# โดยปกติแล้ว... - person Jon Skeet; 11.07.2016
comment
@จอน นิสัยเก่าตายยาก :) - person Jacob Pitts; 11.07.2016

บรรทัดที่สองไม่ใช่วัตถุพจนานุกรมที่ว่างเปล่า ลองเพิ่มเนื้อหาลงในวัตถุพจนานุกรมที่ 2 เพื่อค้นหาตัวคุณเอง โดยทั่วไป คุณจะชี้การอ้างอิงไปที่ null เมื่อคุณต้องการกำหนดวัตถุให้กับการอ้างอิงนั้นในภายหลังในโปรแกรม

person Geek    schedule 11.07.2016

คำตอบง่ายๆ กรณีแรกที่คุณสามารถใช้ กรณีที่สองจะให้ NullReferenceException ในขณะที่คุณดำเนินการนั้น เนื่องจาก null หมายถึงไม่มีอยู่ ดังนั้นคุณจึงไม่สามารถเข้าถึงได้จนกว่าจะมีการสร้างอินสแตนซ์

ไม่มีอะไรผิดปกติกับการประกาศครั้งที่สอง แต่หากคุณต้องการใช้สิ่งนี้หมายความว่าคุณต้องสร้างอินสแตนซ์ (ก่อนใช้งาน) มิฉะนั้นมันจะส่ง NullReferenceException ให้ PopulateDictonary() จะเป็นวิธีการที่จะส่งคืนวัตถุ Dictionary จากนั้นคุณสามารถใช้วิธีนี้เพื่อสร้างอินสแตนซ์ myDictionary

นั่นคือ:

Dictionary<int, List<string>> myDictionary;
// Some code here, Not using myDictionary
myDictionary = PopulateDictonary();

หมายเหตุ: - คุณควรตรวจสอบค่า Null ก่อนที่จะใช้ myDictionary หากคุณใช้การสร้างอินสแตนซ์วัตถุแบบมีเงื่อนไขเพื่อหลีกเลี่ยงข้อยกเว้น

person sujith karivelil    schedule 11.07.2016
comment
มีชื่อว่า NullReferenceException - person Uwe Keim; 11.07.2016
comment
ฉันก็กำลังจะเขียนเหมือนกัน ฉันสามารถเพิ่มคำตอบนี้ได้ว่าคำตอบแรกคุณกำลังสร้างอินสแตนซ์และคำตอบที่สองคุณแค่ประกาศเท่านั้น หากต้องการใช้งาน คุณจะต้องสร้างอินสแตนซ์ ไม่ใช่แค่ประกาศเท่านั้น - person matiaslauriti; 11.07.2016
comment
นี่ไม่ได้อธิบายความแตกต่างอย่างชัดเจน บางทีตัวแปรอาจถูกกำหนดค่าอื่นในภายหลัง... บางทีอาจมีการกำหนดค่า แบบมีเงื่อนไข... และการใช้การอ้างอิง null อาจเป็นเรื่องปกติ ตัวอย่างเช่น อาจถูกส่งผ่านเป็นอาร์กิวเมนต์ไปยังวิธีอื่นซึ่งสามารถจัดการค่าพารามิเตอร์ null ได้ NullReferenceException จะถูกโยนทิ้งเมื่อโค้ดพยายามลดการอ้างอิงค่าเท่านั้น - person Jon Skeet; 11.07.2016
comment
@JonSkeet: ให้ฉันอธิบาย - person sujith karivelil; 11.07.2016
comment
ฉันจะลบอะไรก็ตามเกี่ยวกับค่าเริ่มต้น - นั่นไม่เกี่ยวข้องหากนี่คือการประกาศตัวแปรในเครื่อง และขอย้ำอีกครั้งว่าตัวแปรสามารถนำมาใช้ในแง่ของการส่งผ่านค่าไปยังสิ่งอื่นในขณะที่ยังคงมีค่าว่างอยู่ - person Jon Skeet; 11.07.2016
comment
@JonSkeet: ขอบคุณสำหรับคำแนะนำและการสนับสนุนอันมีค่า - person sujith karivelil; 11.07.2016

มีความแตกต่างมากมายระหว่างสองคำสั่ง คำสั่งพื้นฐานที่สุด: คำสั่งแรกคือการกำหนดค่าเริ่มต้น ในขณะที่คำสั่งหลังเป็นเพียงการประกาศ พิจารณารหัสต่อไปนี้:

Base b = new Derived();

ต่อ

Base b = null;

ในคำสั่งแรก คุณ สร้าง อินสแตนซ์ใหม่ของ Derived และ กำหนด ให้กับ b โดยปกติแล้ว คุณจะต้องมีอินสแตนซ์ของคลาสเพื่อเรียกสมาชิกของคลาส (เพื่อความง่าย เราจะละสมาชิกแบบคงที่ไว้ที่นี่) ในกรณีของคุณ ให้ใช้วิธี Add ที่กำหนดไว้ใน Dictionary เป็นต้น การประกาศ คุณเพียงแค่กำหนดสมาชิกที่คุณอาจเรียกใช้บนอินสแตนซ์ของคลาส อย่างไรก็ตาม ไม่มีการพูดถึงอินสแตนซ์นั้นที่คุณเรียกสมาชิกเหล่านั้น โดยพื้นฐานแล้ว คุณต้องมีข้อมูลสองประการ: สัญญารหัสที่กำหนดโดยอินเทอร์เฟซ (ไม่ใช่ความหมาย OOP) ที่คุณใช้ - ในกรณีของคุณนี่เป็นเพียง Dictionary<int, List<string>> ตอนนี้คุณรู้แล้วว่า อะไร คุณสามารถทำอะไรกับอินสแตนซ์ของคลาสนี้ได้ อย่างไรก็ตาม คุณไม่มี มี อินสแตนซ์ของคลาสตราบใดที่คุณใช้ null-มอบหมาย นี่คือข้อมูลที่สอง - อินสแตนซ์จริง

หากต้องการอยู่ในตัวอย่างก่อนหน้าของฉัน คอมไพลเลอร์ควรรู้ได้อย่างไรว่าคุณใช้คลาส จริง ๆ - Base หรือ Derived สิ่งนี้จะไม่ส่งผลกระทบต่อ สิ่งที่ ที่คุณสามารถทำได้กับอินสแตนซ์โดยไม่จำเป็น (ซึ่งกำหนดโดยคำจำกัดความภายใน Base) แต่ยิ่งไปกว่านั้น วิธี คุณดำเนินการอย่างไร เนื่องจาก Derived อาจมีตรรกะของตัวเอง สำหรับการทำสิ่งต่าง ๆ ที่กำหนดไว้ใน Base

person HimBromBeere    schedule 11.07.2016