Sudahkah event handler ditambahkan?

183

Apakah ada cara untuk mengetahui apakah event handler telah ditambahkan ke objek? Saya membuat serial daftar objek ke / keluar dari status sesi sehingga kita dapat menggunakan status sesi berbasis SQL ... Ketika sebuah objek dalam daftar memiliki properti yang diubah, ia harus ditandai, yang ditangani oleh pawang sebelum ditangani dengan benar sebelum . Namun sekarang ketika objek deserialized itu tidak mendapatkan pengendali event.

Karena agak kesal, saya baru saja menambahkan event handler ke properti Get yang mengakses objek. Sudah dipanggil sekarang, itu bagus, kecuali dipanggil 5 kali jadi saya pikir pawang terus ditambahkan setiap kali objek diakses.

Benar-benar cukup aman untuk diabaikan begitu saja, tetapi saya lebih suka membuatnya lebih bersih dengan memeriksa untuk melihat apakah pawang telah ditambahkan jadi saya hanya melakukannya sekali.

Apakah itu mungkin?

Suntingan: Saya tidak harus memiliki kontrol penuh atas event handler apa yang ditambahkan, jadi hanya memeriksa null saja tidak cukup.

CodeRedick
sumber
lihat juga stackoverflow.com/questions/367523/…
Ian Ringrose

Jawaban:

123

Dari luar kelas pendefinisian, seperti @Telos menyebutkan, Anda hanya dapat menggunakan EventHandler di sisi kiri a +=atau a -=. Jadi, jika Anda memiliki kemampuan untuk memodifikasi kelas yang mendefinisikan, Anda bisa memberikan metode untuk melakukan pemeriksaan dengan memeriksa apakah event handler null- jika demikian, maka tidak ada event handler yang ditambahkan. Jika tidak, maka mungkin dan Anda dapat mengulangi nilai-nilai di Delegate.GetInvocationList . Jika satu sama dengan delegasi yang ingin Anda tambahkan sebagai pengendali acara, maka Anda tahu itu ada di sana.

public bool IsEventHandlerRegistered(Delegate prospectiveHandler)
{   
    if ( this.EventHandler != null )
    {
        foreach ( Delegate existingHandler in this.EventHandler.GetInvocationList() )
        {
            if ( existingHandler == prospectiveHandler )
            {
                return true;
            }
        }
    }
    return false;
}

Dan ini dapat dengan mudah dimodifikasi untuk menjadi "tambahkan pawang jika tidak ada". Jika Anda tidak memiliki akses ke jeroan kelas yang memaparkan acara tersebut, Anda mungkin perlu menjelajah -=dan +=, seperti yang disarankan oleh @Lou Franco.

Namun, Anda mungkin sebaiknya memeriksa kembali cara Anda menugaskan dan menonaktifkan objek-objek ini, untuk melihat apakah Anda tidak dapat menemukan cara untuk melacak informasi ini sendiri.

Blair Conrad
sumber
7
Ini tidak dikompilasi, EventHandler hanya bisa di sisi kiri + = atau - =.
CodeRedick
2
Hapus suara setelah penjelasan lebih lanjut. Status SQL cukup banyak menghancurkan seluruh ide di sini ... :(
CodeRedick
1
Terima kasih Blair dan pencarian SO, hanya apa yang saya cari (mengganggu Anda tidak dapat melakukannya di luar kelas sekalipun)
George Mauer
3
Masalah terjadi sebagian besar waktu saat membandingkan delegasi untuk kesetaraan. Jadi gunakan Delegate.Equals(objA, objB)jika Anda ingin memeriksa keberadaan delegasi yang sama persis. Jika tidak membandingkan sifat individual seperti if(objA.Method.Name == objB.Method.Name && objA.Target.GetType().FullName == objB.Target.GetType().FullName).
Sanjay
2
Kode ini tidak berfungsi di WinForm. Apakah ini hanya untuk ASP.NET?
jp2code
213

Saya baru-baru ini datang ke situasi yang sama di mana saya perlu mendaftarkan pawang untuk suatu peristiwa hanya sekali. Saya menemukan bahwa Anda dapat membatalkan registrasi dengan aman terlebih dahulu, dan kemudian mendaftar lagi, bahkan jika pawang tidak terdaftar sama sekali:

myClass.MyEvent -= MyHandler;
myClass.MyEvent += MyHandler;

Perhatikan bahwa melakukan hal ini setiap kali Anda mendaftar pawang Anda akan memastikan bahwa pawang Anda terdaftar hanya sekali. Kedengarannya seperti latihan yang cukup bagus untuk saya :)

alf
sumber
9
Tampaknya berisiko; jika suatu peristiwa dipecat setelah melepaskan pawang dan sebelum menambahkannya kembali, itu akan terlewatkan.
Jimmy
27
Tentu. Maksudmu itu bukan thread aman. Tapi itu hanya bisa menjadi masalah saat menjalankan beberapa utas atau sejenisnya, yang tidak biasa. Dalam kebanyakan kasus ini harus cukup baik demi kesederhanaan.
alf
7
Ini menggangguku. Hanya karena Anda saat ini tidak secara eksplisit membuat utas dalam kode Anda, itu tidak berarti tidak ada banyak utas, atau tidak akan ditambahkan nanti. Segera setelah Anda (atau orang lain dalam tim, mungkin berbulan-bulan kemudian) menambahkan utas pekerja atau menanggapi UI dan koneksi jaringan, ini membuka pintu untuk kejadian yang sangat terputus-putus.
Technophile
1
Saya percaya rentang waktu antara menghapus dan menambahkan lagi sangat kecil, sehingga sangat tidak mungkin ada peristiwa yang terlewat, tapi ya, itu masih mungkin.
Alisson
2
Jika Anda menggunakan ini untuk sesuatu seperti memperbarui UI dll maka itu tugas sepele risikonya ok. Jika ini untuk penanganan paket jaringan dll maka saya tidak akan menggunakannya.
gulungan
18

Jika ini adalah satu-satunya penangan, Anda dapat memeriksa untuk melihat apakah acara tersebut nol, jika tidak, penangan telah ditambahkan.

Saya pikir Anda dapat dengan aman memanggil - = pada acara dengan handler Anda bahkan jika itu tidak ditambahkan (jika tidak, Anda bisa menangkapnya) - untuk memastikan itu tidak ada di sana sebelum menambahkan.

Lou Franco
sumber
3
Logika ini akan pecah segera setelah acara ditangani di tempat lain juga.
bugged87
6

Contoh ini menunjukkan cara menggunakan metode GetInvocationList () untuk mengambil delegasi ke semua penangan yang telah ditambahkan. Jika Anda mencari untuk melihat apakah penangan tertentu (fungsi) telah ditambahkan maka Anda dapat menggunakan array.

public class MyClass
{
  event Action MyEvent;
}

...

MyClass myClass = new MyClass();
myClass.MyEvent += SomeFunction;

...

Action[] handlers = myClass.MyEvent.GetInvocationList(); //this will be an array of 1 in this example

Console.WriteLine(handlers[0].Method.Name);//prints the name of the method

Anda dapat memeriksa berbagai properti di properti Metode delegasi untuk melihat apakah fungsi tertentu telah ditambahkan.

Jika Anda ingin melihat apakah hanya ada satu lampiran, Anda bisa menguji nol.

Jason Jackson
sumber
GetInvocationList () bukan anggota kelas saya. Sebenarnya, saya tidak dapat menemukan metode ini pada objek atau pengendali mana pun yang dapat saya akses ...
CodeRedick
Saya sudah mencobanya juga, ternyata Anda hanya bisa mengakses acara seperti itu dari dalam kelas. Saya melakukan ini secara umum, dan seperti orang lain telah menyebutkan bahwa penangan acara mungkin tersesat. Terimakasih atas klarifikasinya!
CodeRedick
4

Jika saya memahami masalah Anda dengan benar, Anda mungkin memiliki masalah yang lebih besar. Anda mengatakan bahwa objek lain dapat berlangganan acara ini. Ketika objek serial dan deserialized objek lain (yang Anda tidak memiliki kendali) akan kehilangan event handler mereka.

Jika Anda tidak khawatir tentang hal itu maka menyimpan referensi ke event handler Anda harus cukup baik. Jika Anda khawatir tentang efek samping dari objek lain yang kehilangan event handlernya, maka Anda mungkin ingin memikirkan kembali strategi caching Anda.

CodeChef
sumber
1
Doh! Bahkan tidak memikirkan itu ... meskipun seharusnya sudah jelas mengingat masalah asli saya adalah pawang saya sendiri tersesat.
CodeRedick
2

Saya setuju dengan jawaban ALF, tetapi sedikit modifikasi untuk itu adalah, untuk menggunakan,

           try
            {
                control_name.Click -= event_Click;
                main_browser.Document.Click += Document_Click;
            }
            catch(Exception exce)
            {
                main_browser.Document.Click += Document_Click;
            }
Pengembang perangkat lunak
sumber
2

Satu-satunya cara yang berhasil bagi saya adalah membuat variabel Boolean yang saya setel ke true ketika saya menambahkan acara. Lalu saya bertanya: Jika variabelnya salah, saya menambahkan acara.

bool alreadyAdded = false;

Variabel ini bisa bersifat global.

if(!alreadyAdded)
{
    myClass.MyEvent += MyHandler;
    alreadyAdded = true;
}
Xtian11
sumber
0
EventHandler.GetInvocationList().Length > 0
benPearce
sumber
2
bukankah ini melempar ketika daftar == null?
Boris Callens
2
di luar kelas yang memiliki pengendali event, Anda hanya dapat menggunakan - = dan + =. Anda tidak dapat mengakses acara tersebut.
tbergelt