UPDATE
ตั้งแต่ C # 6 คำตอบสำหรับคำถามนี้คือ:
SomeEvent?.Invoke(this, e);
ฉันมักจะได้ยิน / อ่านคำแนะนำต่อไปนี้:
ทำสำเนาของเหตุการณ์เสมอก่อนที่คุณจะตรวจสอบnull
และดำเนินการ การทำเช่นนี้จะช่วยขจัดปัญหาที่อาจเกิดขึ้นกับเธรดที่เหตุการณ์เกิดขึ้นnull
ที่ตำแหน่งระหว่างที่คุณตรวจสอบว่ามีค่าว่างหรือไม่
// Copy the event delegate before checking/calling
EventHandler copy = TheEvent;
if (copy != null)
copy(this, EventArgs.Empty); // Call any handlers on the copied list
อัปเดต : ฉันคิดว่าจากการอ่านเกี่ยวกับการปรับให้เหมาะสมซึ่งสิ่งนี้อาจต้องการให้สมาชิกเหตุการณ์ระเหยได้ แต่ Jon Skeet ระบุไว้ในคำตอบของเขาว่า CLR ไม่ได้เพิ่มประสิทธิภาพการคัดลอก
แต่ในขณะเดียวกันเพื่อให้ปัญหานี้เกิดขึ้นอีกเธรดอื่นต้องทำดังนี้:
// Better delist from event - don't want our handler called from now on:
otherObject.TheEvent -= OnTheEvent;
// Good, now we can be certain that OnTheEvent will not run...
ลำดับที่แท้จริงอาจเป็นส่วนผสมนี้:
// Copy the event delegate before checking/calling
EventHandler copy = TheEvent;
// Better delist from event - don't want our handler called from now on:
otherObject.TheEvent -= OnTheEvent;
// Good, now we can be certain that OnTheEvent will not run...
if (copy != null)
copy(this, EventArgs.Empty); // Call any handlers on the copied list
จุดที่OnTheEvent
ทำงานหลังจากผู้เขียนได้ยกเลิกการสมัครและยังพวกเขาเพียงยกเลิกการสมัครสมาชิกโดยเฉพาะเพื่อหลีกเลี่ยงสิ่งที่เกิดขึ้น สิ่งที่จำเป็นจริงๆคือการปรับใช้เหตุการณ์ที่กำหนดเองด้วยการซิงโครไนซ์ที่เหมาะสมในadd
และremove
อุปกรณ์ และนอกจากนี้ยังมีปัญหาการหยุดชะงักที่เป็นไปได้หากล็อคจะถูกจัดขึ้นในขณะที่เหตุการณ์ถูกไล่ออก
ดังนั้นการเขียนโปรแกรม Cargo ลัทธินี้คืออะไร? ดูเหมือนว่า - ผู้คนจำนวนมากต้องทำตามขั้นตอนนี้เพื่อปกป้องรหัสของพวกเขาจากหลายเธรดเมื่อในความเป็นจริงฉันคิดว่าเหตุการณ์ต้องใช้ความระมัดระวังมากกว่านี้ก่อนที่พวกเขาจะสามารถใช้เป็นส่วนหนึ่งของการออกแบบแบบมัลติเธรด . ดังนั้นผู้ที่ไม่ได้รับการดูแลเพิ่มเติมอาจเพิกเฉยต่อคำแนะนำนี้ - มันไม่ใช่ปัญหาสำหรับโปรแกรมแบบเธรดเดียวและในความเป็นจริงหากไม่มีvolatile
รหัสตัวอย่างออนไลน์ส่วนใหญ่คำแนะนำอาจไม่มี ผลกระทบทั้งหมด
(และมันง่ายกว่าไหมถ้าเพียงแค่กำหนดค่าว่างdelegate { }
ในการประกาศสมาชิกเพื่อให้คุณไม่จำเป็นต้องตรวจสอบnull
ตั้งแต่แรก)
Updated:ในกรณีที่ไม่ชัดเจนฉันเข้าใจถึงความตั้งใจของคำแนะนำ - เพื่อหลีกเลี่ยงข้อยกเว้นการอ้างอิงที่เป็นโมฆะในทุกสถานการณ์ ประเด็นของฉันคือข้อยกเว้นการอ้างอิง null นี้สามารถเกิดขึ้นได้หากเธรดอื่นถูกเพิกถอนจากเหตุการณ์และเหตุผลเดียวที่ทำเช่นนั้นคือเพื่อให้แน่ใจว่าจะไม่มีการรับสายอีกต่อไปผ่านเหตุการณ์นั้นซึ่งเทคนิคนี้ไม่สามารถทำได้อย่างชัดเจน . คุณต้องการปกปิดสภาพการแข่งขัน - มันจะเป็นการดีกว่าถ้าคุณเปิดเผยมัน! ข้อยกเว้น null นั้นช่วยในการตรวจสอบการละเมิดส่วนประกอบของคุณ หากคุณต้องการให้องค์ประกอบของคุณได้รับการปกป้องจากการละเมิดคุณสามารถทำตามตัวอย่างของ WPF - เก็บ ID เธรดในตัวสร้างของคุณแล้วโยนข้อยกเว้นหากเธรดอื่นพยายามโต้ตอบโดยตรงกับส่วนประกอบของคุณ หรือใช้ส่วนประกอบของเธรดที่ปลอดภัยอย่างแท้จริง (ไม่ใช่เรื่องง่าย)
ดังนั้นฉันขอยืนยันว่าการทำสำเนา / ตรวจสอบสำนวนนี้เป็นการเขียนโปรแกรมลัทธิสินค้าเท่านั้นเพิ่มความยุ่งเหยิงและเสียงรบกวนให้กับรหัสของคุณ เพื่อป้องกันเธรดอื่น ๆ จริง ๆ ต้องใช้งานมากขึ้น
อัปเดตเพื่อตอบสนองต่อบล็อกของ Eric Lippert:
ดังนั้นมีสิ่งสำคัญที่ฉันพลาดเกี่ยวกับตัวจัดการเหตุการณ์: "ตัวจัดการเหตุการณ์จำเป็นต้องแข็งแกร่งในหน้าของการถูกเรียกแม้ว่าจะยกเลิกการสมัครกิจกรรม" และแน่นอนดังนั้นเราจึงต้องดูแลเกี่ยวกับความเป็นไปได้ของเหตุการณ์ null
ผู้รับมอบสิทธิ์ความเป็นอยู่ ข้อกำหนดเกี่ยวกับตัวจัดการเหตุการณ์นั้นมีการบันทึกไว้ทุกที่หรือไม่?
ดังนั้น: "มีวิธีอื่นในการแก้ปัญหานี้ตัวอย่างเช่นการเริ่มต้นตัวจัดการเพื่อให้มีการกระทำที่ว่างเปล่าที่ไม่เคยถูกลบออกไป แต่การตรวจสอบค่า null เป็นรูปแบบมาตรฐาน"
ดังนั้นคำถามที่เหลืออีกส่วนหนึ่งของฉันคือทำไมจึงชัดเจน - โมฆะ - ตรวจสอบ "รูปแบบมาตรฐาน"? อีกทางเลือกหนึ่งคือการมอบหมายผู้แทนที่ว่างเปล่าจะต้อง= delegate {}
ถูกเพิ่มเข้าไปในการประกาศกิจกรรมเท่านั้นและนี่จะเป็นการขจัดพิธีเล็ก ๆ เหล่านั้นให้หมดไปจากทุกที่ที่มีการจัดงาน มันจะง่ายต่อการตรวจสอบให้แน่ใจว่าผู้รับมอบสิทธิ์ที่ว่างเปล่านั้นราคาถูกในการสร้างอินสแตนซ์ หรือฉันยังขาดอะไรอยู่
แน่นอนว่าต้องเป็นอย่างนั้น (ตามที่ Jon Skeet แนะนำ) นี่เป็นเพียงคำแนะนำ. NET 1.x ที่ยังไม่ตายเหมือนที่ควรจะทำในปี 2005?
EventName(arguments)
เรียกตัวแทนของเหตุการณ์โดยไม่มีเงื่อนไขแทนที่จะให้มันเรียกเฉพาะผู้รับมอบสิทธิ์หากไม่ใช่ค่าว่าง (ไม่ทำอะไรเลยถ้าไม่มีค่า)