Urutan eksekusi event handler


93

Jika saya menyiapkan beberapa penangan acara, seperti ini:

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

urutan apa yang dijalankan penangan saat acara RetrieveDataCompleteddipecat? Apakah mereka berjalan di utas yang sama dan berurutan dalam urutan yang terdaftar?


2
Jawabannya akan spesifik untuk acara RetrieveDataCompleted. Jika memiliki penyimpanan dukungan default dari delegasi multi-cast, maka ya "mereka berjalan di thread yang sama dan secara berurutan dalam urutan yang terdaftar".
HappyNomad

Jawaban:


133

Saat ini, mereka dieksekusi sesuai urutan mereka terdaftar. Namun, ini adalah detail implementasi, dan saya tidak akan mengandalkan perilaku ini tetap sama di versi mendatang, karena tidak diwajibkan oleh spesifikasi.


6
Saya bertanya-tanya, mengapa suara negatifnya? Ini benar, dan menjawab pertanyaan secara langsung ...
Reed Copsey

2
@Rawling: Itu untuk resolusi kelebihan beban operator biner - bukan penanganan event. Ini bukan operator penjumlahan, dalam kasus ini.
Reed Copsey

2
Ah, saya mengerti kesalahan saya: "Penangan acara adalah delegasi, bukan?". Sekarang saya tahu mereka tidak. Telah menulis sendiri peristiwa yang memicu penangan dalam urutan terbalik, hanya untuk membuktikannya pada diri saya sendiri :)
Rawling

16
Untuk memperjelas, pesanan bergantung pada penyimpanan dukungan untuk acara tertentu. Penyimpanan cadangan default untuk acara, delegasi multi-cast, didokumentasikan sebagai dijalankan dalam urutan pendaftaran. Ini tidak akan berubah dalam versi kerangka kerja yang akan datang. Apa yang mungkin berubah adalah penyimpanan dukungan yang digunakan untuk acara tertentu.
HappyNomad

6
Tidak disukai karena secara faktual salah pada 2 poin. 1) Saat ini mereka dieksekusi dalam urutan yang ditentukan oleh implementasi acara tertentu - karena Anda dapat menerapkan metode tambah / hapus Anda sendiri untuk acara. 2) Saat menggunakan implementasi acara default melalui delegasi multi-cast, urutan sebenarnya diperlukan oleh spesifikasi.
Søren Boisen

53

Daftar pemanggilan delegasi adalah sekumpulan delegasi yang diurutkan di mana setiap elemen daftar memanggil tepat satu metode yang dipanggil oleh delegasi. Daftar permintaan dapat berisi metode duplikat. Selama pemanggilan, seorang delegasi memanggil metode dalam urutan kemunculannya dalam daftar pemanggilan .

Dari sini: Kelas Delegasi


1
Bagus, tetapi menggunakan kata kunci adddan removesebuah acara belum tentu diimplementasikan sebagai delegasi multi-pemain.
HappyNomad

Seperti halnya Bob , jawaban lain menyebutkan bahwa penggunaan ini dengan event handler adalah sesuatu yang harus dianggap tidak dapat diandalkan ... apakah itu benar atau tidak, jawaban ini juga bisa berbicara tentang itu.
n611x007

12

Anda dapat mengubah urutan dengan melepaskan semua penangan, lalu memasang kembali dalam urutan yang diinginkan.

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

Urutannya sewenang-wenang. Anda tidak dapat mengandalkan penangan yang dieksekusi dalam urutan tertentu dari satu pemanggilan ke pemanggilan berikutnya.

Sunting: Dan juga - kecuali ini hanya karena ingin tahu - fakta yang perlu Anda ketahui merupakan indikasi masalah desain yang serius .


3
Urutannya bergantung pada implementasi peristiwa tertentu, tetapi tidak sewenang - wenang. Kecuali jika dokumentasi acara menunjukkan urutan permintaan, saya setuju berisiko untuk bergantung padanya. Dalam nada itu, saya memposting pertanyaan lanjutan .
HappyNomad

9
Untuk memiliki acara yang perlu ditangani oleh kelas yang berbeda dalam urutan partircular tampaknya bukan masalah desain yang serius bagi saya. Masalah akan terjadi jika registrasi event dilakukan dengan cara yang membuat sulit untuk mengetahui order atau event untuk mengetahui bahwa order itu penting.
Ignacio Soler Garcia

8

Mereka dijalankan sesuai urutan pendaftarannya. RetrieveDataCompletedadalah Delegasi Multicast . Saya melihat melalui reflektor untuk mencoba dan memverifikasi, dan sepertinya array digunakan di belakang layar untuk melacak semuanya.


jawaban lain mencatat bahwa dengan event handler ini adalah 'tidak disengaja', 'rapuh', 'detail implementasi', dll., mis. tidak disyaratkan oleh standar atau konvensi apa pun, itu terjadi begitu saja. Apakah itu benar? bagaimanapun juga, jawaban ini bisa merujuk pada hal itu juga.
n611x007

3

Jika seseorang perlu melakukan ini dalam konteks System.Windows.Forms.Form, berikut adalah contoh membalik urutan acara Tampil.

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 memiliki daftar delegasi yang ditautkan, yang disebut daftar permintaan, yang terdiri dari satu atau lebih elemen. Saat delegasi multicast dipanggil, delegasi dalam daftar pemanggilan dipanggil secara sinkron dalam urutan kemunculannya. Jika kesalahan terjadi selama eksekusi daftar maka pengecualian dilemparkan.


2

Selama pemanggilan, metode dipanggil dalam urutan kemunculannya dalam daftar pemanggilan.

Tetapi tidak ada yang mengatakan bahwa daftar pemanggilan mempertahankan delegasi dalam urutan yang sama saat mereka ditambahkan. Dengan demikian, urutan permintaan tidak dijamin.


1

Ini adalah fungsi yang akan menempatkan fungsi penanganan kejadian baru di mana pun Anda inginkan dalam daftar pemanggilan multidelegate.

    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);
    }

Kemudian Anda selalu dapat menghapus fungsi dengan '- =' di mana pun dalam kode Anda.

PS - Saya tidak melakukan penanganan kesalahan untuk parameter 'posisi'.


0

Saya punya masalah serupa. Dalam kasus saya, itu diperbaiki dengan sangat mudah. Saya belum pernah melihat delegasi yang tidak menggunakan operator + =. Masalah saya diperbaiki dengan memiliki satu delegasi yang selalu ditambahkan di akhir, yang lainnya selalu ditambahkan di awal. Contoh OP akan menjadi seperti ini:

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

Dalam kasus pertama, ProcessData1 akan dipanggil terakhir. Dalam kasus kedua, ProcessData2 akan dipanggil terlebih dahulu.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.