TLDR: นี่เป็นข้อผิดพลาดที่รู้จักกันมานาน ฉันแรกเขียนเกี่ยวกับเรื่องนี้ในปี 2010:
https://blogs.msdn.microsoft.com/ericlippert/2010/01/18/a-definite-assignment-anomaly/
มันไม่เป็นอันตรายและคุณสามารถเพิกเฉยได้อย่างปลอดภัยและขอแสดงความยินดีกับการค้นหาบั๊กที่ค่อนข้างคลุมเครือ
ทำไมคอมไพเลอร์ไม่บังคับใช้ที่Emailต้องกำหนดอย่างแน่นอน?
โอ้มันเป็นไปตามแฟชั่น มันมีความคิดผิด ๆ ว่าเงื่อนไขใดที่บอกเป็นนัย ๆ ว่าตัวแปรนั้นถูกกำหนดอย่างแน่นอนตามที่เราจะได้เห็น
ทำไมรหัสนี้จึงคอมไพล์ถ้ามีการสร้าง struct ในชุดประกอบที่แยกต่างหาก แต่จะไม่รวบรวมถ้ามีการกำหนด struct ในชุดประกอบที่มีอยู่
นั่นคือจุดเริ่มต้นของข้อบกพร่อง บั๊กเป็นผลมาจากการตัดกันของวิธีคอมไพเลอร์ C # ทำการตรวจสอบการมอบหมายที่ชัดเจนใน structs และวิธีที่คอมไพเลอร์โหลดข้อมูลเมตาจากไลบรารี
พิจารณาสิ่งนี้:
struct Foo
{
public int x;
public int y;
}
// Yes, public fields are bad, but this is just
// to illustrate the situation.
void M(out Foo f)
{
ตกลง ณ จุดนี้เรารู้อะไร fเป็นนามแฝงสำหรับตัวแปรชนิดFooดังนั้นที่เก็บข้อมูลได้ถูกจัดสรรแล้วและอย่างน้อยก็ในสถานะที่มันออกมาจากตัวจัดสรรพื้นที่จัดเก็บ หากมีค่าอยู่ในตัวแปรโดยผู้เรียกค่านั้นจะมี
เราต้องการอะไร เราต้องการให้fมีการมอบหมายอย่างแน่นอน ณ จุดใดก็ตามที่การควบคุมออกไปMตามปกติ ดังนั้นคุณจะคาดหวังสิ่งที่ชอบ:
void M(out Foo f)
{
f = new Foo();
}
ซึ่งกำหนดf.xและf.yเป็นค่าเริ่มต้น แต่แล้วเรื่องนี้ล่ะ
void M(out Foo f)
{
f = new Foo();
f.x = 123;
f.y = 456;
}
นั่นก็ควรจะดี แต่และนี่คือนักเตะเหตุใดเราจึงต้องกำหนดค่าเริ่มต้นให้ระเบิดออกไปในภายหลัง ตัวตรวจสอบการกำหนดที่ชัดเจนของ C # จะตรวจสอบเพื่อดูว่ามีการกำหนดทุกฟิลด์หรือไม่! สิ่งนี้ถูกกฎหมาย:
void M(out Foo f)
{
f.x = 123;
f.y = 456;
}
และทำไมจึงไม่ถูกกฎหมาย? มันเป็นประเภทค่า fเป็นตัวแปรและมันมีค่าประเภทที่ถูกต้องอยู่แล้วFooดังนั้นลองตั้งค่าเขตข้อมูลและเราเสร็จแล้วใช่ไหม
ขวา. ดังนั้นบั๊กคืออะไร
ข้อผิดพลาดที่คุณได้ค้นพบคือ การประหยัดค่าใช้จ่าย, C # คอมไพเลอร์ไม่ได้โหลดข้อมูลเมตาสำหรับเขตข้อมูลส่วนตัวของ structs ที่อยู่ในห้องสมุดอ้างอิง ข้อมูลเมตานั้นมีขนาดใหญ่มากและมันจะทำให้คอมไพเลอร์ช้าลงเพื่อให้ชนะน้อยมากเพื่อโหลดมันทั้งหมดลงในหน่วยความจำทุกครั้ง
และตอนนี้คุณน่าจะสามารถสรุปสาเหตุของข้อผิดพลาดที่คุณพบ เมื่อคอมไพเลอร์ตรวจสอบว่าพารามิเตอร์ out ได้รับการกำหนดแน่นอนจะทำการเปรียบเทียบจำนวนของเขตข้อมูลที่รู้จักกับจำนวนของเขตข้อมูลที่ได้รับการกำหนดค่าเริ่มต้นแน่นอนและในกรณีของคุณจะรู้เกี่ยวกับเขตข้อมูลสาธารณะเป็นศูนย์เท่านั้น. คอมไพเลอร์สรุป "จำเป็นต้องกรอกข้อมูลในฟิลด์ให้เป็นศูนย์, เริ่มต้นเป็นศูนย์แล้ว, เราทำได้ดี"
อย่างที่ฉันพูดข้อผิดพลาดนี้เกิดขึ้นมานานกว่าทศวรรษแล้วและคนอย่างคุณค้นพบมันใหม่เป็นครั้งคราวและรายงานปัญหา ไม่เป็นอันตรายและไม่น่าจะได้รับการแก้ไขเพราะการซ่อมเป็นประโยชน์เกือบเป็นศูนย์ แต่มีต้นทุนประสิทธิภาพสูง
และแน่นอนข้อผิดพลาดไม่ได้ทำซ้ำสำหรับเขตข้อมูลส่วนตัวของ struct ที่อยู่ในซอร์สโค้ดในโครงการของคุณเพราะเห็นได้ชัดว่าคอมไพเลอร์มีข้อมูลเกี่ยวกับเขตข้อมูลส่วนตัวที่อยู่ในมือแล้ว