ผู้ส่งเหตุการณ์ควรเป็นวัตถุทั่วไปหรือไม่


10

เมื่อกิจกรรมการเขียนโปรแกรมใน C # ขอแนะนำให้สร้างผู้แทนในรูปแบบของ:

delegate XEventHandler(object sender, XEventArgs e);

คำถามของฉันอยู่ที่อาร์กิวเมนต์แรกของผู้รับมอบสิทธิ์object sender. มันจำเป็นต้องเป็นยาสามัญobjectหรือไม่? การมีผู้ส่งเป็นประเภทobjectจะส่งผลให้เกิดรหัสคล้ายกัน

val = ((ConcreteType)sender).Property;

หรือยิ่ง verbose

ConcreteType obj = sender as ConcreteType
if (obj != null) { ... }

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

ถ้าคลาสของผู้ส่งเป็นที่รู้จักกันเสมอ (อย่างน้อยก็เป็นคลาสนามธรรม)? ตัวอย่างเช่นถ้าฉันกำลังดำเนินการListChangedจัดกิจกรรมในนามธรรมListชั้นและถ้าชั้นเรียนอื่น ๆ จะได้รับมรดก (เช่นLinkedList, ArrayList) มันเป็นสิทธิ์ที่จะกำหนดผู้รับมอบสิทธิ์ของฉันที่มีผู้ส่งประเภทList?

delegate ListChangedEventHander(List sender, ListChangedEventArgs e);

หรือว่าจะมีข้อเสียของการเปลี่ยนแบบเดิมobject senderเป็นแบบเฉพาะเจาะจงมากขึ้น?

คำตอบ:


10

ณ จุดนี้มันเป็นแบบแผน (ค่อนข้างแข็งแกร่ง) เป็นส่วนใหญ่ นั่นคือมันจะแปลกถ้าคุณเขียนไลบรารีที่ไม่เป็นไปตามแบบแผนนั้น

แนวทางการออกแบบเหตุการณ์กล่าวว่า

DOใช้เป็นชนิดของพารามิเตอร์แรกของการจัดการเหตุการณ์และเรียกมันว่าobjectsender

อย่างไรก็ตามคุณอาจทราบว่าคำแนะนำปัจจุบันบอกว่าคุณไม่ควรกำหนดผู้รับมอบสิทธิ์ที่กำหนดเองสำหรับกิจกรรม แต่ควรใช้EventHandler<T>แทนหากคุณทำได้

สำหรับการออกแบบนั้นฉันคิดว่ามันส่งเสริมการใช้งานตัวจัดการเหตุการณ์ซ้ำอีกครั้งแม้ในบริบทที่ไม่ได้คาดการณ์ไว้โดยนักออกแบบดั้งเดิมของเหตุการณ์


2
อืม ... เพียงเพราะ Microsoft ตัดสินใจที่จะทำแนวทางทั่วไปพอที่จะใช้กับทุกคนไม่ได้หมายความว่ามันเป็นความคิดที่ดีสำหรับทุกคนที่จะปฏิบัติตามแนวทางของพวกเขา โอกาสเป็นไปได้อย่างมากว่า "คนอื่น ๆ " ไม่ได้เขียนรหัสเพื่อใช้งานโดยนักพัฒนาอื่น ๆ นับล้าน ฉันลองดูคำแนะนำจากลิงก์ที่คุณให้ไว้ประมาณ 2/3
Dunk

เพื่อบอกความจริงกับคุณ "แนวทาง" นี้ให้ความรู้สึกมากขึ้นหรือน้อยลงราวกับสัญกรณ์ฮังการีของ Windows API มีคนที่ยอดเยี่ยมเริ่มต้นด้วยเหตุผลที่ดีจริงๆจากนั้นทุกคนก็เริ่มใช้มันในทางที่ผิด เมื่อมีแนวทางก็จะมีเหตุผลที่ดีที่อยู่เบื้องหลังแนวทางนั้น และสิ่งที่ผมคิดว่าเหตุผลสำหรับแนวทางนี้ก็คือว่าSystem.Windows.Formsnamespace เป็นสถานที่ที่เหตุการณ์ที่เกิดขึ้นมีการใช้มากที่สุดและมันทำให้ความรู้สึกที่จะสมัครเป็นสมาชิกกับClickกรณีของหรือButton CheckBoxดังนั้นผู้ส่งต้องการที่จะเป็นทั่วไป ...
sampathsris

... แต่เมื่อพูดถึงพื้นที่อื่นที่มีความเฉพาะเจาะจงมากขึ้นของฟังก์ชันการทำงานผู้ส่งอาจไม่จำเป็นต้องเป็นคลาสทั่วไป ดูตัวอย่างของฉันอีกครั้งของลำดับชั้นของLists
sampathsris

11
@Dunk: และนั่นคือจุด แนวทางนี้มาจาก Framework Design Guidelines ซึ่งส่วนใหญ่เกี่ยวข้องกับรหัสที่ผู้อื่นใช้ ไม่ใช่เพราะมันเป็นทางออกที่ดีที่สุด แต่เพราะมันเป็นสิ่งที่น่าประหลาดใจน้อยที่สุด นั่นเป็นตัวเลือกที่ดีที่สุดสำหรับกรอบ สำหรับไลบรารี่ขนาดเล็กถ้ามีการระบุกรณีการใช้อย่างดี Microsoft บอกอย่างชัดเจนตั้งแต่ต้นหนังสือ
Magus

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

0

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

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

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.