โครงสร้างที่มีฟิลด์หรือคุณสมบัติที่ไม่แน่นอนสาธารณะไม่ได้เลวร้าย
วิธีการโครงสร้าง (แตกต่างจากตัวตั้งค่าคุณสมบัติ) ซึ่งกลายพันธุ์ "นี่" ค่อนข้างเลวร้ายเพียงเพราะ. net ไม่ได้ให้วิธีการแยกพวกเขาจากวิธีการที่ไม่ วิธีการสร้างที่ไม่ได้กลายพันธุ์ "นี้" ควรจะเรียกใช้แม้ในโครงสร้างแบบอ่านอย่างเดียวโดยไม่จำเป็นต้องคัดลอกเพื่อป้องกัน วิธีการที่ทำให้กลายพันธุ์ "นี้" ไม่ควรเรียกใช้กับโครงสร้างแบบอ่านอย่างเดียว เนื่องจาก. net ไม่ต้องการห้ามวิธีการ struct ที่ไม่แก้ไข "this" จากการเรียกใช้บนแบบอ่านอย่างเดียว แต่ไม่ต้องการให้กลายเป็นแบบอ่านอย่างเดียวกลายพันธุ์มันจึงคัดลอก struct ในแบบอ่านอย่างละเอียด บริบทเท่านั้นเนื้อหาที่ได้รับที่เลวร้ายที่สุดของโลกทั้งสอง
แม้จะมีปัญหากับการจัดการวิธีการกลายพันธุ์ด้วยตนเองในบริบทแบบอ่านอย่างเดียวอย่างไรก็ตามโครงสร้างที่ไม่แน่นอนมักจะให้ความหมายที่เหนือกว่าประเภทคลาสที่ไม่แน่นอน พิจารณาลายเซ็นวิธีการสามข้อต่อไปนี้:
struct PointyStruct {public int x, y, z;};
คลาส PointyClass {public int x, y, z;};
ถือเป็นโมฆะ Method1 (PointyStruct foo);
ถือเป็นโมฆะ Method2 (อ้างอิง PointyStruct foo);
ถือเป็นโมฆะ Method3 (PointyClass foo);
สำหรับแต่ละวิธีให้ตอบคำถามต่อไปนี้:
- สมมติว่าวิธีการไม่ใช้รหัส "ไม่ปลอดภัย" มันจะแก้ไข foo หรือไม่
- หากไม่มีการอ้างอิงภายนอกไปยัง 'foo' ก่อนที่จะมีการเรียกเมธอดการอ้างอิงภายนอกจะมีอยู่หลังจากนั้นหรือไม่?
คำตอบ:
คำถามที่ 1::
Method1()
ไม่มี(เจตนาชัดเจน)
Method2()
: ใช่(เจตนาชัดเจน)
Method3()
: ใช่(เจตนาไม่แน่นอน)
คำถามที่ 2
Method1()
:: ไม่
Method2()
: ไม่ใช่(ยกเว้นไม่ปลอดภัย)
Method3()
: ใช่
วิธีที่ 1 ไม่สามารถแก้ไข foo และไม่เคยได้รับการอ้างอิง Method2 ได้รับการอ้างอิงแบบสั้น ๆ เกี่ยวกับ foo ซึ่งสามารถใช้แก้ไขฟิลด์ของ foo ได้หลายครั้งในลำดับใด ๆ จนกว่าจะส่งคืน แต่ก็ไม่สามารถยืนยันการอ้างอิงนั้นได้ ก่อนที่ Method2 จะส่งคืนเว้นแต่ว่าจะใช้รหัสที่ไม่ปลอดภัยสำเนาใด ๆ และทั้งหมดที่อาจทำจากการอ้างอิง 'foo' จะหายไป วิธีที่ 3 ซึ่งแตกต่างจากวิธีที่ 2 ได้รับการอ้างอิงที่คมชัดที่คมชัดเพื่อ foo และไม่มีการบอกว่ามันอาจทำอะไรกับมัน มันอาจไม่เปลี่ยน foo เลยก็อาจเปลี่ยน foo แล้วกลับมาหรืออาจให้การอ้างอิง foo ไปยังเธรดอื่นซึ่งอาจกลายพันธุ์ในบางวิธีโดยพลการในเวลาอนาคตโดยพลการ
อาร์เรย์ของโครงสร้างมีความหมายที่ยอดเยี่ยม กำหนด RectArray [500] ชนิดสี่เหลี่ยมผืนผ้ามันชัดเจนและชัดเจนวิธีการคัดลอกองค์ประกอบ 123 องค์ประกอบ 456 และจากนั้นบางครั้งในภายหลังตั้งความกว้างขององค์ประกอบ 123 ถึง 555 โดยไม่รบกวนองค์ประกอบ 456 "RectArray [432] = RectArray [321 ]; ... ; RectArray [123] .Width = 555; " การรู้ว่า Rectangle เป็น struct ที่มีเขตข้อมูลจำนวนเต็มที่เรียกว่า Width จะบอกสิ่งที่ทุกคนต้องการทราบเกี่ยวกับข้อความข้างต้น
ทีนี้สมมติว่า RectClass เป็นคลาสที่มีเขตข้อมูลเดียวกับสี่เหลี่ยมผืนผ้าและอีกหนึ่งต้องการดำเนินการแบบเดียวกันกับ RectClassArray [500] ประเภท RectClass บางทีอาเรย์ควรจะเก็บไว้ 500 อ้างอิงล่วงหน้าไม่เปลี่ยนรูปไปยังวัตถุ RectClass ไม่แน่นอน ในกรณีนั้นรหัสที่เหมาะสมจะเป็นอะไรเช่น "RectClassArray [321] .BoundBase (RectClassArray [456]); ... ; RectClassArray [321] .X = 555;" บางทีอาร์เรย์อาจถูกสมมติให้เก็บอินสแตนซ์ที่จะไม่เปลี่ยนแปลงดังนั้นรหัสที่เหมาะสมจะเป็นเช่น "RectClassArray [321] = RectClassArray [456]; ... ; RectClassArray [321] = ใหม่ RectClassArray [321] ]); RectClassArray [321] .X = 555; " หากต้องการทราบสิ่งที่ควรทำเราจะต้องรู้มากขึ้นทั้งเกี่ยวกับ RectClass (เช่นรองรับตัวสร้างสำเนา, วิธีคัดลอกจาก ฯลฯ ) ) และการใช้งานที่ตั้งใจของอาร์เรย์ ไม่มีที่ไหนใกล้สะอาดเท่าการใช้ struct
เพื่อให้แน่ใจว่าไม่มีวิธีที่ดีสำหรับคลาสคอนเทนเนอร์ใด ๆ นอกเหนือจากอาเรย์เพื่อให้ความหมายที่ชัดเจนของอาร์เรย์อาเรย์ สิ่งที่ดีที่สุดสามารถทำได้หากต้องการให้มีการจัดทำดัชนีเช่นสตริงอาจจะเสนอวิธีทั่วไป "ActOnItem" ซึ่งจะยอมรับสตริงสำหรับดัชนีพารามิเตอร์ทั่วไปและผู้รับมอบสิทธิ์ที่จะผ่าน โดยอ้างอิงทั้งพารามิเตอร์ทั่วไปและรายการคอลเลกชัน ที่จะช่วยให้เกือบจะมีความหมายเช่นเดียวกับ struct อาเรย์ แต่ถ้า vb.net และ C # คนสามารถติดตามเพื่อเสนอไวยากรณ์ที่ดีรหัสจะเป็น clunky ดูแม้ว่าจะมีประสิทธิภาพที่สมเหตุสมผล (ผ่านพารามิเตอร์ทั่วไปจะ อนุญาตให้ใช้ผู้รับมอบสิทธิ์แบบคงที่และจะหลีกเลี่ยงความต้องการสร้างอินสแตนซ์คลาสชั่วคราวใด ๆ )
โดยส่วนตัวแล้วฉันรู้สึกเกลียดชังที่ Eric Lippert และคณะ spew เกี่ยวกับประเภทค่าที่ไม่แน่นอน พวกเขามีความหมายที่สะอาดกว่าประเภทอ้างอิงที่หลากหลายที่ใช้กันทั่วสถานที่ แม้จะมีข้อ จำกัด บางประการกับการสนับสนุน. net สำหรับประเภทค่ามีหลายกรณีที่ประเภทค่าที่ไม่แน่นอนสามารถปรับให้พอดีได้ดีกว่าเอนทิตีชนิดอื่น
int
s,bool
s และค่าชนิดอื่น ๆ ทั้งหมดนั้นเป็นความชั่วร้าย มีหลายกรณีสำหรับความแปรปรวนและการเปลี่ยนแปลงไม่ได้ กรณีเหล่านี้ขึ้นอยู่กับบทบาทที่เล่นข้อมูลไม่ใช่ประเภทของการจัดสรร / แชร์หน่วยความจำ