ลำดับของการดำเนินการตัวจัดการเหตุการณ์


94

หากฉันตั้งค่าตัวจัดการเหตุการณ์หลายตัวเช่น:

_webservice.RetrieveDataCompleted += ProcessData1;
_webservice.RetrieveDataCompleted += ProcessData2;

สิ่งที่สั่งซื้อจะถูกขนย้ายวัสดุทำงานเมื่อมีเหตุการณ์RetrieveDataCompletedยิง? พวกเขาทำงานในเธรดเดียวกันและเรียงตามลำดับตามลำดับที่ลงทะเบียนหรือไม่?


2
คำตอบจะเฉพาะเจาะจงสำหรับเหตุการณ์ RetrieveDataCompleted หากมีที่เก็บสำรองเริ่มต้นของผู้รับมอบสิทธิ์แบบหลายคนแสดงว่าใช่ "พวกเขาทำงานในเธรดเดียวกันและเรียงตามลำดับตามลำดับที่ลงทะเบียน"
HappyNomad

คำตอบ:


133

ปัจจุบันมีการดำเนินการตามลำดับที่ลงทะเบียน อย่างไรก็ตามนี่เป็นรายละเอียดการใช้งานและฉันจะไม่พึ่งพาพฤติกรรมนี้ที่ยังคงเหมือนเดิมในเวอร์ชันอนาคตเนื่องจากไม่จำเป็นต้องใช้ตามข้อกำหนด


6
ฉันสงสัยว่าทำไมถึงโหวตลง? นี่เป็นความจริงและตอบคำถามโดยตรง ...
Reed Copsey

2
@Rawling: นั่นคือสำหรับความละเอียดเกินพิกัดของตัวดำเนินการไบนารี - ไม่ใช่การจัดการเหตุการณ์ นี่ไม่ใช่ตัวดำเนินการเพิ่มเติมในกรณีนี้
Reed Copsey

2
อ่าฉันเห็นว่าฉันทำอะไรผิด: "ตัวจัดการเหตุการณ์คือผู้รับมอบสิทธิ์ใช่ไหม" ตอนนี้ฉันรู้แล้วว่ามันไม่ใช่ ได้เขียนเหตุการณ์ให้ตัวเองยิงตัวจัดการในลำดับย้อนกลับเพื่อพิสูจน์ให้ตัวเองเห็น :)
Rawling

16
เพื่อชี้แจงคำสั่งซื้อขึ้นอยู่กับร้านค้าสำรองสำหรับเหตุการณ์เฉพาะ ที่เก็บสำรองเริ่มต้นสำหรับเหตุการณ์ผู้รับมอบสิทธิ์แบบหลายคาสต์ได้รับการบันทึกว่าดำเนินการตามลำดับการลงทะเบียน สิ่งนี้จะไม่เปลี่ยนแปลงในเวอร์ชันกรอบอนาคต สิ่งที่อาจเปลี่ยนแปลงได้คือ Backing Store ที่ใช้สำหรับเหตุการณ์หนึ่ง ๆ
HappyNomad

6
ลดลงเนื่องจากไม่ถูกต้องใน 2 คะแนน 1) ขณะนี้มีการดำเนินการตามลำดับที่การใช้งานเหตุการณ์เฉพาะกำหนด - เนื่องจากคุณสามารถใช้วิธีการเพิ่ม / ลบของคุณเองสำหรับเหตุการณ์ได้ 2) เมื่อใช้การใช้งานเหตุการณ์เริ่มต้นผ่านตัวแทนหลายคนในความเป็นจริงคำสั่งนั้นเป็นข้อกำหนดที่กำหนด
Søren Boisen

53

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

จากที่นี่: Delegate Class


1
ดี แต่การใช้addและremoveคำหลักเหตุการณ์อาจไม่จำเป็นต้องนำมาใช้ในฐานะผู้รับมอบสิทธิ์แบบหลายคน
HappyNomad

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

12

คุณสามารถเปลี่ยนลำดับได้โดยการถอดตัวจัดการทั้งหมดจากนั้นติดใหม่ตามลำดับที่ต้องการ

public event EventHandler event1;

public void ChangeHandlersOrdering()
{
    if (event1 != null)
    {
        List<EventHandler> invocationList = event1.GetInvocationList()
                                                  .OfType<EventHandler>()
                                                  .ToList();

        foreach (var handler in invocationList)
        {
            event1 -= handler;
        }

        //Change ordering now, for example in reverese order as follows
        for (int i = invocationList.Count - 1; i >= 0; i--)
        {
            event1 += invocationList[i];
        }
    }
}

10

คำสั่งเป็นไปโดยพลการ คุณไม่สามารถพึ่งพาตัวจัดการที่กำลังดำเนินการตามลำดับใด ๆ จากการร้องขอหนึ่งไปยังอีก

แก้ไข:และนอกจากนี้ - นอกจากความอยากรู้อยากเห็น - ความจริงที่คุณจำเป็นต้องรู้นั้นบ่งบอกถึงปัญหาการออกแบบที่ร้ายแรง


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

9
การมีเหตุการณ์ที่ต้องจัดการโดยชั้นเรียนต่างๆตามลำดับขั้นตอนดูเหมือนจะไม่เป็นปัญหาในการออกแบบที่ร้ายแรงสำหรับฉัน ปัญหาจะเกิดขึ้นหากการลงทะเบียนเหตุการณ์ทำในลักษณะที่ทำให้ยากที่จะทราบคำสั่งซื้อหรือเหตุการณ์เพื่อให้ทราบว่าคำสั่งนั้นสำคัญ
Ignacio Soler Garcia

8

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


คำตอบอื่น ๆ โปรดทราบว่าด้วยตัวจัดการเหตุการณ์นี่คือ 'โดยบังเอิญ' 'เปราะบาง', 'รายละเอียดการนำไปใช้งาน' ฯลฯ กล่าวคือ ไม่จำเป็นต้องใช้ตามมาตรฐานหรืออนุสัญญาใด ๆ มันเพิ่งเกิดขึ้น นั่นถูกต้องใช่ไหม? ไม่ว่าในกรณีใดคำตอบนี้อาจอ้างถึงสิ่งนั้นด้วย
n611x007

3

หากมีคนต้องการทำสิ่งนี้ในบริบทของ System.Windows.Forms.Form ต่อไปนี้เป็นตัวอย่างการสลับลำดับเหตุการณ์ที่แสดง

using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;

namespace ConsoleApplication {
    class Program {
        static void Main() {
            Form form;

            form = createForm();
            form.ShowDialog();

            form = createForm();
            invertShownOrder(form);
            form.ShowDialog();
        }

        static Form createForm() {
            var form = new Form();
            form.Shown += (sender, args) => { Console.WriteLine("form_Shown1"); };
            form.Shown += (sender, args) => { Console.WriteLine("form_Shown2"); };
            return form;
        }

        static void invertShownOrder(Form form) {
            var events = typeof(Form)
                .GetProperty("Events", BindingFlags.Instance | BindingFlags.NonPublic)
                .GetValue(form, null) as EventHandlerList;

            var shownEventKey = typeof(Form)
                .GetField("EVENT_SHOWN", BindingFlags.NonPublic | BindingFlags.Static)
                .GetValue(form);

            var shownEventHandler = events[shownEventKey] as EventHandler;

            if (shownEventHandler != null) {
                var invocationList = shownEventHandler
                    .GetInvocationList()
                    .OfType<EventHandler>()
                    .ToList();

                foreach (var handler in invocationList) {
                    events.RemoveHandler(shownEventKey, handler);
                }

                for (int i = invocationList.Count - 1; i >= 0; i--) {
                    events.AddHandler(shownEventKey, invocationList[i]);
                }
            }
        }
    }
}

2

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


2

ในระหว่างการเรียกใช้เมธอดจะถูกเรียกตามลำดับที่ปรากฏในรายการการเรียกใช้

แต่ไม่มีใครบอกว่ารายการเรียกใช้จะรักษาผู้รับมอบสิทธิ์ไว้ในลำดับเดียวกับที่เพิ่มเข้าไป ดังนั้นจึงไม่รับประกันการสั่งซื้อ


1

นี่คือฟังก์ชันที่จะวางฟังก์ชันตัวจัดการเหตุการณ์ใหม่ทุกที่ที่คุณต้องการในรายการการเรียกใช้ผู้ร่วมประชุมหลายคน

    private void addDelegateAt(ref YourDelegate initial, YourDelegate newHandler, int position)
    {
        Delegate[] subscribers = initial.GetInvocationList();
        Delegate[] newSubscriptions = new Delegate[subscribers.Length + 1];

        for (int i = 0; i < newSubscriptions.Length; i++)
        {
            if (i < position)
                newSubscriptions[i] = subscribers[i];
            else if (i==position)
                newSubscriptions[i] = (YourDelegate)newHandler;
            else if (i > position)
                newSubscriptions[i] = subscribers[i-1];
        }

        initial = (YourDelegate)Delegate.Combine(newSubscriptions);
    }

จากนั้นคุณสามารถลบฟังก์ชันได้ตลอดเวลาด้วยเครื่องหมาย '- =' ทุกที่ในรหัสของคุณสะดวก

ป.ล. - ฉันไม่ได้จัดการข้อผิดพลาดใด ๆ สำหรับพารามิเตอร์ 'ตำแหน่ง'


0

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

    _webservice.RetrieveDataCompleted = _webservice.RetrieveDataCompleted + ProcessData1;
    _webservice.RetrieveDataCompleted = ProcessData2 + _webservice.RetrieveDataCompleted;

ในกรณีแรก ProcessData1 จะถูกเรียกล่าสุด ในกรณีที่ 2 ProcessData2 จะถูกเรียกก่อน

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