ความแตกต่างที่สำคัญที่สุดระหว่าง a class
และ a struct
คือสิ่งที่เกิดขึ้นในสถานการณ์ต่อไปนี้:
สิ่งสิ่งที่ 1 = สิ่งใหม่ ();
thing1.somePropertyOrField = 5;
สิ่งที่สิ่งที่ 2 = สิ่งที่ 1;
thing2.somePropertyOrField = 9;
สิ่งที่ควรเป็นผลกระทบของคำสั่งสุดท้ายเมื่อthing1.somePropertyOrField
? หากThing
struct และsomePropertyOrField
เป็นสัมผัสข้อมูลสาธารณะวัตถุthing1
และthing2
จะเป็น "เดี่ยว" จากแต่ละอื่น ๆ thing1
เพื่อให้คำสั่งหลังจะไม่ส่งผลกระทบ หากThing
เป็นชั้นแล้วthing1
และthing2
จะแนบไปกับแต่ละอื่น ๆ thing1.somePropertyOrField
และเพื่อให้คำสั่งหลังจะเขียน หนึ่งควรใช้โครงสร้างในกรณีที่ความหมายในอดีตจะทำให้รู้สึกมากขึ้นและควรใช้ชั้นเรียนในกรณีที่ความหมายหลังจะทำให้รู้สึกมากขึ้น
โปรดทราบว่าในขณะที่บางคนแนะนำว่าความปรารถนาที่จะทำสิ่งที่ไม่แน่นอนนั้นเป็นข้อโต้แย้งเพราะมันเป็นคลาส แต่ฉันขอแนะนำให้ย้อนกลับเป็นความจริง: ถ้าสิ่งที่มีอยู่เพื่อจุดประสงค์ในการเก็บข้อมูลบางอย่างนั้นจะไม่แน่นอนและ หากไม่ชัดเจนว่ามีการเชื่อมต่ออินสแตนซ์กับสิ่งใดก็ตามสิ่งนั้นควรเป็นโครงสร้าง (น่าจะเป็นกับฟิลด์ที่เปิดเผย) เพื่อให้ชัดเจนว่าอินสแตนซ์นั้นไม่ได้เชื่อมต่อกับสิ่งอื่นใด
ตัวอย่างเช่นพิจารณาข้อความ:
คน somePerson = myPeople.GetPerson ("123-45-6789");
somePerson.Name = "Mary Johnson"; // เป็น "Mary Smith"
ข้อความที่สองจะเปลี่ยนแปลงข้อมูลที่เก็บไว้myPeople
หรือไม่? ถ้าPerson
เป็นโครงสร้างเขตข้อมูลที่เปิดเผยมันจะไม่และความจริงที่ว่ามันจะไม่เป็นผลที่ชัดเจนของการเป็นโครงสร้างเขตข้อมูลที่เปิดเผย ; ถ้าPerson
เป็น struct และต้องการจะอัปเดตmyPeople
เราจะต้องทำอะไรบางอย่างอย่างmyPeople.UpdatePerson("123-45-6789", somePerson)
ชัดเจน หากPerson
เป็นคลาสอย่างไรก็ตามอาจเป็นการยากกว่าที่จะระบุว่ารหัสข้างต้นจะไม่อัปเดตเนื้อหาของMyPeople
อัปเดตทุกครั้งหรือบางครั้งอัปเดต
จากความเห็นเกี่ยวกับความคิดที่ว่าโครงสร้างควรจะ "ไม่เปลี่ยนรูป" ฉันไม่เห็นด้วยโดยทั่วไป มีกรณีการใช้งานที่ถูกต้องสำหรับโครงสร้าง "ที่ไม่เปลี่ยนรูป" (ซึ่งมีการบังคับใช้ค่าคงที่ในตัวสร้าง) แต่กำหนดให้โครงสร้างทั้งหมดต้องถูกเขียนใหม่ทุกครั้งที่ส่วนใดส่วนหนึ่งของการเปลี่ยนแปลงนั้นเป็นที่น่าอึดอัดใจสิ้นเปลืองและมีแนวโน้มมากขึ้น เขตข้อมูลโดยตรง ยกตัวอย่างเช่นพิจารณาPhoneNumber
struct ที่มีสาขารวมถึงหมู่คนอื่น ๆAreaCode
และและคิดว่าคนมีExchange
List<PhoneNumber>
ผลกระทบของสิ่งต่อไปนี้ควรชัดเจน:
สำหรับ (int i = 0; i <myList.Count; i ++)
{
หมายเลขโทรศัพท์ theNumber = myList [i];
if (theNumber.AreaCode == "312")
{
string newExchange = "";
if (new312to708Exchanges.TryGetValue (theNumber.Exchange), ออก newExchange)
{
theNumber.AreaCode = "708";
theNumber.Exchange = newExchange;
myList [i] = theNumber;
}
}
}
หมายเหตุว่าไม่มีอะไรในรหัสข้างต้นรู้หรือใส่ใจเกี่ยวกับเขตข้อมูลใด ๆ ในPhoneNumber
อื่น ๆ กว่าและAreaCode
Exchange
หากPhoneNumber
เป็นสิ่งที่เรียกว่า "ไม่เปลี่ยนรูป" struct ก็จะมีความจำเป็นอย่างใดอย่างหนึ่งที่ให้withXX
วิธีการสำหรับแต่ละเขตข้อมูลซึ่งจะส่งกลับอินสแตนซ์ struct ใหม่ซึ่งเก็บค่าที่ส่งผ่านในเขตข้อมูลที่ระบุหรืออื่น ๆ มันจะจำเป็น สำหรับโค้ดอย่างที่รู้ด้านบนเกี่ยวกับทุกฟิลด์ในโครงสร้าง ไม่น่าสนใจอย่างแน่นอน
BTW มีอย่างน้อยสองกรณีที่ structs อาจเก็บการอ้างอิงถึงชนิดที่ไม่แน่นอน
- ซีแมนทิกส์ของโครงสร้างระบุว่ามันเก็บข้อมูลประจำตัวของวัตถุที่เป็นปัญหาแทนที่จะเป็นทางลัดสำหรับเก็บคุณสมบัติของวัตถุ ตัวอย่างเช่น "KeyValuePair" จะเก็บเอกลักษณ์ของปุ่มบางปุ่ม แต่คาดว่าจะไม่เก็บข้อมูลถาวรเกี่ยวกับตำแหน่งของปุ่มเหล่านั้นสถานะไฮไลต์ ฯลฯ
- โครงสร้างรู้ว่ามันเก็บการอ้างอิงเพียงอย่างเดียวกับวัตถุนั้นไม่มีใครจะได้รับการอ้างอิงและการกลายพันธุ์ใด ๆ ที่จะถูกดำเนินการกับวัตถุนั้นจะได้รับการดำเนินการก่อนที่จะมีการอ้างอิงไปยังที่ใดก็ได้
ในสถานการณ์สมมติก่อนหน้านี้ IDENTITY ของวัตถุจะไม่เปลี่ยนรูป ในครั้งที่สองคลาสของวัตถุที่ซ้อนกันอาจไม่บังคับใช้ไม่ได้ แต่โครงสร้างที่เก็บการอ้างอิงจะ