MEMPERBARUI
Mulai dari C # 6, jawaban untuk pertanyaan ini adalah:
SomeEvent?.Invoke(this, e);
Saya sering mendengar / membaca saran berikut:
Selalu buat salinan acara sebelum Anda memeriksanya null
dan memecatnya. Ini akan menghilangkan potensi masalah dengan threading di mana acara tersebut terjadinull
berada di lokasi yang tepat di antara tempat Anda memeriksa nol dan tempat Anda memecat acara:
// Copy the event delegate before checking/calling
EventHandler copy = TheEvent;
if (copy != null)
copy(this, EventArgs.Empty); // Call any handlers on the copied list
Diperbarui : Saya berpikir dari membaca tentang optimasi bahwa ini mungkin juga mengharuskan anggota acara menjadi tidak stabil, tetapi Jon Skeet menyatakan dalam jawabannya bahwa CLR tidak mengoptimalkan salinan.
Tetapi sementara itu, agar masalah ini terjadi, utas lainnya pasti telah melakukan sesuatu seperti ini:
// 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...
Urutan sebenarnya mungkin campuran ini:
// 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
Intinya adalah itu OnTheEvent
berjalan setelah penulis telah berhenti berlangganan, namun mereka hanya berhenti berlangganan khusus untuk menghindari hal itu terjadi. Tentunya yang benar-benar dibutuhkan adalah implementasi acara kustom dengan sinkronisasi yang sesuai di add
dan remove
accessor. Dan di samping itu ada masalah kemungkinan kebuntuan jika kunci ditahan saat suatu peristiwa dipecat.
Begitu juga Pemrograman Kargo Kargo ini ? Sepertinya begitu - banyak orang harus mengambil langkah ini untuk melindungi kode mereka dari banyak utas, padahal dalam kenyataannya menurut saya peristiwa memerlukan jauh lebih banyak perhatian daripada ini sebelum mereka dapat digunakan sebagai bagian dari desain multi-utas . Akibatnya, orang-orang yang tidak mengambil perawatan tambahan mungkin juga mengabaikan saran ini - itu bukan masalah untuk program single-threaded, dan pada kenyataannya, mengingat tidak adanya volatile
sebagian besar kode contoh online, saran tersebut mungkin tidak memiliki efek sama sekali.
(Dan bukankah jauh lebih mudah untuk hanya menetapkan yang kosong delegate { }
pada deklarasi anggota sehingga Anda tidak perlu memeriksa null
sejak awal?)
Diperbarui:Jika tidak jelas, saya memahami maksud dari saran - untuk menghindari pengecualian referensi nol dalam semua keadaan. Maksud saya adalah pengecualian referensi nol khusus ini hanya dapat terjadi jika utas lain menghapus daftar acara, dan satu-satunya alasan untuk melakukan itu adalah untuk memastikan bahwa tidak ada panggilan lebih lanjut akan diterima melalui peristiwa itu, yang jelas TIDAK BISA dicapai dengan teknik ini . Anda akan menyembunyikan kondisi balapan - akan lebih baik untuk mengungkapkannya! Pengecualian nol itu membantu mendeteksi penyalahgunaan komponen Anda. Jika Anda ingin komponen Anda dilindungi dari penyalahgunaan, Anda dapat mengikuti contoh WPF - simpan ID utas di konstruktor Anda dan kemudian berikan pengecualian jika utas lain mencoba berinteraksi langsung dengan komponen Anda. Atau menerapkan komponen yang benar-benar aman (bukan tugas yang mudah).
Jadi saya berpendapat bahwa hanya melakukan ini copy / cek idiom adalah pemrograman kargo, menambahkan kekacauan dan kebisingan ke kode Anda. Untuk benar-benar melindungi dari utas lainnya membutuhkan lebih banyak pekerjaan.
Pembaruan dalam menanggapi posting blog Eric Lippert:
Jadi ada hal utama yang saya lewatkan tentang penangan acara: "penangan acara harus kuat dalam menghadapi dipanggil bahkan setelah acara telah berhenti berlangganan", dan jelas karena itu kita hanya perlu peduli tentang kemungkinan acara mendelegasikan keberadaan null
. Apakah persyaratan pada penangan acara didokumentasikan di mana saja?
Maka: "Ada cara lain untuk menyelesaikan masalah ini; misalnya, menginisialisasi pawang untuk memiliki tindakan kosong yang tidak pernah dihapus. Tetapi melakukan pemeriksaan nol adalah pola standar."
Jadi satu fragmen yang tersisa dari pertanyaan saya adalah, mengapa eksplisit-nol-periksa "pola standar"? Alternatif, menugaskan delegasi kosong, hanya = delegate {}
perlu ditambahkan ke deklarasi acara, dan ini menghilangkan tumpukan-tumpukan kecil upacara bau dari setiap tempat di mana acara dibesarkan. Akan mudah untuk memastikan bahwa delegasi yang kosong murah untuk instantiate. Atau apakah saya masih melewatkan sesuatu?
Pasti itu (seperti yang disarankan Jon Skeet) ini hanya .NET 1.x saran yang belum padam, seperti yang seharusnya dilakukan pada tahun 2005?
EventName(arguments)
memanggil delegasi acara tanpa syarat, daripada meminta delegasi acara hanya jika tidak nol (tidak melakukan apa pun jika nol).