Sebuah acara deklarasi menambahkan lapisan abstraksi dan perlindungan pada delegasi misalnya. Perlindungan ini mencegah klien dari delegasi mengatur ulang delegasi dan daftar doa dan hanya memungkinkan menambah atau menghapus target dari daftar doa.
Jika tentu saja, lapisan perlindungan ini juga mencegah "klien" (kode di luar kelas / struct yang mendefinisikan) dari memanggil delegasi, dan dari cara apa pun mendapatkan objek delegasi "di belakang" acara.
Jeppe Stig Nielsen
7
Tidak sepenuhnya benar. Anda dapat mendeklarasikan suatu peristiwa tanpa instance delegasi backend. Di c #, Anda dapat mengimplementasikan suatu peristiwa secara eksplisit dan menggunakan struktur data backend yang berbeda dari pilihan Anda.
Miguel Gamboa
3
@mmcdole dapatkah Anda memberikan contoh untuk menjelaskan tentangnya?
vivek nuna
103
Untuk memahami perbedaan Anda dapat melihat 2 contoh ini
Contoh dengan Delegasi (dalam hal ini, Aksi - itu adalah semacam delegasi yang tidak mengembalikan nilai)
Untuk menggunakan delegasi, Anda harus melakukan sesuatu seperti ini:
Animal animal=newAnimal();
animal.Run+=()=>Console.WriteLine("I'm running");
animal.Run+=()=>Console.WriteLine("I'm still running");
animal.RaiseEvent();
Kode ini berfungsi dengan baik tetapi Anda dapat memiliki beberapa titik lemah.
Misalnya, jika saya menulis ini:
animal.Run+=()=>Console.WriteLine("I'm running");
animal.Run+=()=>Console.WriteLine("I'm still running");
animal.Run=()=>Console.WriteLine("I'm sleeping");
dengan baris kode terakhir, saya telah menimpa perilaku sebelumnya hanya dengan satu yang hilang +(saya telah menggunakan =alih-alih +=)
Kelemahan lain adalah bahwa setiap kelas yang menggunakan Animalkelas Anda dapat meningkatkan RaiseEventhanya dengan menyebutnya animal.RaiseEvent().
Untuk menghindari titik-titik lemah ini Anda dapat menggunakan eventsc #.
Kelas Hewan Anda akan berubah dengan cara ini:
publicclassArgsSpecial:EventArgs{publicArgsSpecial(string val){Operation=val;}publicstringOperation{get;set;}}publicclassAnimal{// Empty delegate. In this way you are sure that value is always != null // because no one outside of the class can change it.publiceventEventHandler<ArgsSpecial>Run=delegate{}publicvoidRaiseEvent(){Run(this,newArgsSpecial("Run faster"));}}
untuk memanggil acara
Animal animal=newAnimal();
animal.Run+=(sender, e)=>Console.WriteLine("I'm running. My value is {0}", e.Operation);
animal.RaiseEvent();
Perbedaan:
Anda tidak menggunakan properti publik tetapi bidang publik (menggunakan acara, kompiler melindungi bidang Anda dari akses yang tidak diinginkan)
Acara tidak dapat ditugaskan secara langsung. Dalam hal ini, itu tidak akan memunculkan kesalahan sebelumnya yang telah saya tunjukkan dengan mengesampingkan perilaku.
Tidak seorang pun di luar kelas Anda yang dapat mengangkat acara.
Acara dapat dimasukkan dalam deklarasi antarmuka, sedangkan bidang tidak bisa
Semuanya tampak hebat sampai saya menemukan "Tidak ada seorang pun di luar kelas Anda yang dapat mengangkat acara." Apa artinya? Tidak bisakah ada yang menelepon RaiseEventselama metode panggilan memiliki akses ke instance animaldalam kode yang menggunakan acara?
dance2die
11
@Sung Events hanya bisa dinaikkan dari dalam kelas, mungkin saya belum jelas menjelaskannya. Dengan peristiwa, Anda dapat memanggil fungsi yang membangkitkan peristiwa (enkapsulasi), tetapi hanya dapat dibangkitkan dari dalam kelas yang mendefinisikannya. Beri tahu saya jika saya tidak jelas.
@faby, Maksud Anda meskipun acara ini dinyatakan sebagai publik, saya masih tidak bisa melakukannya animal.Run(this, new ArgsSpecial("Run faster");?
Pap
1
@ChieltenBrinke Tentu saja acara ini dapat ditugaskan di dalam anggota kelas ... tetapi tidak sebaliknya.
Jim Balter
94
Selain sifat sintaksis dan operasional, ada juga perbedaan semantik.
Delegasi, secara konseptual, templat fungsi; yaitu, mereka menyatakan suatu kontrak yang harus dipatuhi oleh suatu fungsi untuk dipertimbangkan dari "tipe" delegasi.
Acara mewakili ... baik, acara. Mereka dimaksudkan untuk memperingatkan seseorang ketika sesuatu terjadi dan ya, mereka mematuhi definisi delegasi tetapi mereka bukan hal yang sama.
Bahkan jika mereka persis hal yang sama (secara sintaksis dan dalam kode IL) masih akan tetap ada perbedaan semantik. Secara umum saya lebih suka memiliki dua nama yang berbeda untuk dua konsep yang berbeda, bahkan jika mereka diimplementasikan dengan cara yang sama (yang tidak berarti saya suka memiliki kode yang sama dua kali).
Jadi dapatkah kita mengatakan bahwa suatu acara adalah jenis delegasi yang "istimewa"?
Pap
Saya tidak mengerti maksud Anda. Anda dapat menggunakan delegasi untuk 'mengingatkan seseorang ketika sesuatu terjadi'. Mungkin Anda tidak akan melakukan itu, tetapi Anda bisa dan karena itu bukan properti yang melekat pada acara.
steve
@Jorge Córdoba contoh delegasi dan acara delegasi adalah pemilik dan acara koran (Berlangganan atau berhenti berlangganan) dan beberapa orang membeli koran dan beberapa orang tidak membeli koran berarti pemilik surat kabar tidak dapat memaksa setiap orang untuk membeli koran, maksud saya benar atau salah?
Secara singkat, pengambilan dari artikel - Acara adalah enkapsulasi atas delegasi.
Kutipan dari artikel:
Misalkan acara tidak ada sebagai konsep di C # /. NET. Bagaimana kelas lain berlangganan suatu acara? Tiga opsi:
Variabel delegasi publik
Variabel delegasi yang didukung oleh properti
Variabel delegasi dengan metode AddXXXHandler dan RemoveXXXHandler
Opsi 1 jelas mengerikan, untuk semua alasan normal kami membenci variabel publik.
Opsi 2 sedikit lebih baik, tetapi memungkinkan pelanggan untuk secara efektif menimpa satu sama lain - itu akan terlalu mudah untuk menulis someInstance.MyEvent = eventHandler; yang akan menggantikan penangan acara yang ada daripada menambahkan yang baru. Selain itu, Anda masih perlu menulis properti.
Opsi 3 pada dasarnya adalah acara yang memberi Anda, tetapi dengan konvensi yang dijamin (dihasilkan oleh kompiler dan didukung oleh bendera tambahan di IL) dan implementasi "gratis" jika Anda senang dengan semantik yang diberikan acara seperti lapangan kepada Anda. Berlangganan dan berhenti berlangganan dari acara dienkapsulasi tanpa mengizinkan akses sewenang-wenang ke daftar penangan acara, dan bahasa dapat membuat segalanya lebih mudah dengan memberikan sintaksis untuk deklarasi dan berlangganan.
Ini lebih merupakan perhatian teoritis daripada apa pun, tetapi FWIW saya selalu merasa seperti "Opsi 1 buruk karena kami tidak suka variabel publik" argumen bisa menggunakan klarifikasi sedikit lebih. Jika dia mengatakan itu karena "praktik OOP buruk", secara teknis suatu public Delegatevariabel akan mengekspos "data", tetapi Delegatesejauh pengetahuan saya, OOP tidak pernah menyebut konsep apa pun seperti (itu bukan "objek" atau "pesan") ,.
jrh
Walaupun saya juga ingin memberikan saran yang lebih praktis, jika Anda berada dalam situasi di mana Anda ingin memastikan bahwa hanya ada satu penangan, membuat AddXXXHandlermetode Anda sendiri dengan private Delegatevariabel mungkin merupakan pilihan yang baik. Dalam hal ini Anda dapat memeriksa untuk melihat apakah pawang sudah diatur, dan bereaksi dengan tepat. Ini juga bisa menjadi pengaturan yang baik jika Anda membutuhkan objek yang memegang Delegateuntuk dapat menghapus semua penangan ( eventtidak memberi Anda cara untuk melakukan ini).
jrh
7
CATATAN: Jika Anda memiliki akses ke C # 5.0 Unleashed , baca "Batasan Penggunaan Utusan Delegasi" di Bab 18 berjudul "Acara" untuk memahami lebih baik perbedaan di antara keduanya.
Selalu membantu saya untuk memiliki contoh yang sederhana dan konkret. Jadi, ini satu untuk komunitas. Pertama saya tunjukkan bagaimana Anda bisa menggunakan delegasi sendirian untuk melakukan apa yang dilakukan Acara untuk kami. Lalu saya tunjukkan bagaimana solusi yang sama akan bekerja dengan contoh EventHandler. Dan kemudian saya jelaskan mengapa kita TIDAK ingin melakukan apa yang saya jelaskan pada contoh pertama. Posting ini terinspirasi oleh sebuah artikel oleh John Skeet.
Contoh 1: Menggunakan delegasi publik
Misalkan saya memiliki aplikasi WinForms dengan satu kotak drop-down. Drop-down terikat ke List<Person>. Di mana Orang memiliki properti Id, Nama, Nama Panggilan, Warna Rambut. Pada formulir utama adalah kontrol pengguna kustom yang menunjukkan properti orang itu. Ketika seseorang memilih seseorang di drop-down label di pembaruan kontrol pengguna untuk menunjukkan properti orang yang dipilih.
Inilah cara kerjanya. Kami memiliki tiga file yang membantu kami menyatukan ini:
Mediator.cs - kelas statis menampung delegasi
Form1.cs - formulir utama
DetailView.cs - kontrol pengguna menampilkan semua detail
Berikut adalah kode yang relevan untuk masing-masing kelas:
classMediator{publicdelegatevoidPersonChangedDelegate(Person p);//delegate type definitionpublicstaticPersonChangedDelegatePersonChangedDel;//delegate instance. Detail view will "subscribe" to this.publicstaticvoidOnPersonChanged(Person p)//Form1 will call this when the drop-down changes.{if(PersonChangedDel!=null){PersonChangedDel(p);}}}
Akhirnya kami memiliki kode berikut di Form1.cs kami. Di sini kita Memanggil OnPersonChanged, yang memanggil kode apa saja yang berlangganan delegasi.
privatevoid comboBox1_SelectedIndexChanged(object sender,EventArgs e){Mediator.OnPersonChanged((Person)comboBox1.SelectedItem);//Call the mediator's OnPersonChanged method. This will in turn call all the methods assigned (i.e. subscribed to) to the delegate -- in this case `DetailView_PersonChanged`.}
Baik. Jadi begitulah cara Anda membuatnya bekerja tanpa menggunakan acara dan hanya menggunakan delegasi . Kami hanya menempatkan delegasi publik ke dalam kelas - Anda dapat membuatnya statis atau tunggal, atau apa pun. Bagus.
NAMUN, NAMUN, NAMUN, kami tidak ingin melakukan apa yang baru saja saya jelaskan di atas. Karena bidang publik buruk karena banyak, banyak alasan. Jadi apa saja pilihan kita? Seperti yang dijelaskan oleh John Skeet, berikut adalah opsi kami:
Variabel delegasi publik (ini adalah apa yang baru saja kita lakukan di atas. Jangan lakukan ini. Saya baru saja memberi tahu Anda mengapa ini buruk)
Tempatkan delegasi ke properti dengan get / set (masalah di sini adalah bahwa pelanggan dapat saling menimpa - sehingga kami dapat berlangganan banyak metode untuk delegasi dan kemudian kami dapat secara tidak sengaja mengatakan PersonChangedDel = null, menghapus semua langganan lainnya. Masalah lain yang tetap ada di sini adalah karena pengguna memiliki akses ke delegasi, mereka dapat meminta target dalam daftar doa - kami tidak ingin pengguna eksternal memiliki akses kapan harus meningkatkan acara kami.
Variabel delegasi dengan metode AddXXXHandler dan RemoveXXXHandler
Opsi ketiga ini pada dasarnya adalah apa yang diberikan oleh suatu peristiwa kepada kita. Ketika kami mendeklarasikan EventHandler, itu memberi kami akses ke delegasi - tidak secara publik, bukan sebagai properti, tetapi karena hal ini kami sebut acara yang baru saja menambah / menghapus pengakses.
Mari kita lihat seperti apa program yang sama, tetapi sekarang menggunakan Acara alih-alih delegasi publik (Saya juga mengubah Mediator kami menjadi singleton):
Contoh 2: Dengan EventHandler alih-alih delegasi publik
Penengah:
classMediator{privatestaticreadonlyMediator_Instance=newMediator();privateMediator(){}publicstaticMediatorGetInstance(){return_Instance;}publiceventEventHandler<PersonChangedEventArgs>PersonChanged;//this is just a property we expose to add items to the delegate.publicvoidOnPersonChanged(object sender,Person p){var personChangedDelegate =PersonChangedasEventHandler<PersonChangedEventArgs>;if(personChangedDelegate !=null){
personChangedDelegate(sender,newPersonChangedEventArgs(){Person= p });}}}
Perhatikan bahwa jika Anda F12 pada EventHandler, itu akan menunjukkan kepada Anda bahwa definisi tersebut hanyalah sebuah delegasi umum dengan objek "pengirim" tambahan:
Semoga itu menunjukkan kepada Anda sedikit tentang mengapa kami memiliki acara dan bagaimana mereka berbeda - tetapi secara fungsional sama - seperti delegasi.
Sementara saya menghargai semua pekerjaan baik dalam posting ini dan saya senang membaca sebagian besar, saya masih merasa satu masalah tidak ditangani - The other problem that remains here is that since the users have access to the delegate, they can invoke the targets in the invocation list -- we don't want external users having access to when to raise our events. Di versi terbaru Mediator, Anda masih dapat menelepon OnPersonChangekapan pun Anda memiliki referensi ke singleton. Mungkin Anda harus menyebutkan bahwa Mediatorpendekatan itu tidak mencegah perilaku tertentu, dan lebih dekat ke bus peristiwa.
Ivaylo Slavov
6
Anda juga dapat menggunakan acara dalam deklarasi antarmuka, tidak demikian untuk delegasi.
@surfen Interface dapat berisi acara, tetapi bukan delegasi.
Alexandr Nikitin
1
Apa sebenarnya maksud Anda? Anda dapat memiliki Action a { get; set; }di dalam definisi antarmuka.
Chiel ten Brinke
6
Benar-benar kesalahpahaman antara acara dan delegasi !!! Delegasi menentukan JENIS (seperti class, atau interfacetidak), sedangkan acara hanya semacam ANGGOTA (seperti bidang, properti, dll). Dan, sama seperti anggota lainnya, acara juga memiliki tipe. Namun, dalam hal acara, jenis acara harus ditentukan oleh delegasi. Misalnya, Anda TIDAK BISA mendeklarasikan peristiwa dari jenis yang ditentukan oleh antarmuka.
Sebagai penutup, kita dapat melakukan Pengamatan berikut : jenis acara HARUS ditentukan oleh delegasi . Ini adalah hubungan utama antara acara dan delegasi dan dijelaskan dalam bagian II.18 Mendefinisikan peristiwa dari ECMA-335 (CLI) Partisi Saya ke VI :
Dalam penggunaan umum, TypeSpec (jika ada) mengidentifikasi delegasi yang tanda tangannya cocok dengan argumen yang diteruskan ke metode api acara.
Namun, fakta ini TIDAK menyiratkan bahwa suatu peristiwa menggunakan bidang delegasi dukungan . Sebenarnya, suatu peristiwa dapat menggunakan bidang dukungan dari berbagai jenis struktur data pilihan Anda. Jika Anda mengimplementasikan suatu acara secara eksplisit dalam C #, Anda bebas untuk memilih cara Anda menyimpan penangan acara (perhatikan bahwa penangan acara adalah contoh dari jenis acara , yang pada gilirannya adalah wajib merupakan jenis delegasi --- dari Pengamatan sebelumnya) ). Tetapi, Anda bisa menyimpan event handler tersebut (yang merupakan contoh delegasi) dalam struktur data seperti a Listatau a Dictionaryatau yang lain, atau bahkan dalam bidang delegasi pendukung. Tapi jangan lupa bahwa TIDAK wajib Anda menggunakan bidang delegasi.
Peristiwa di .net adalah kombinasi yang ditunjuk dari metode Tambahkan dan metode Hapus, yang keduanya mengharapkan beberapa jenis delegasi tertentu. Baik C # maupun vb.net dapat membuat kode secara otomatis untuk metode tambah dan hapus yang akan menentukan delegasi untuk menahan langganan acara, dan menambah / menghapus delegasi yang diteruskan ke / dari delegasi berlangganan tersebut. VB.net juga akan menghasilkan kode secara otomatis (dengan pernyataan RaiseEvent) untuk memohon daftar langganan jika dan hanya jika tidak kosong; untuk beberapa alasan, C # tidak menghasilkan yang terakhir.
Perhatikan bahwa walaupun umum untuk mengelola langganan acara menggunakan delegasi multicast, itu bukan satu-satunya cara untuk melakukannya. Dari perspektif publik, calon pelanggan acara perlu tahu cara memberi tahu objek bahwa ia ingin menerima acara, tetapi tidak perlu tahu mekanisme apa yang akan digunakan penerbit untuk mengangkat acara tersebut. Perhatikan juga bahwa sementara siapa pun yang mendefinisikan struktur data acara di .net tampaknya berpikir harus ada sarana publik untuk meningkatkannya, baik C # maupun vb.net tidak menggunakan fitur itu.
Untuk mendefinisikan tentang acara dengan cara sederhana:
Acara adalah REFERENSI untuk seorang delegasi dengan dua batasan
Tidak dapat dipanggil secara langsung
Tidak dapat menetapkan nilai secara langsung (mis. EventObj = delegateMethod)
Di atas dua adalah titik lemah untuk delegasi dan ditangani jika terjadi. Contoh kode lengkap untuk menunjukkan perbedaan dalam fiddler ada di sini https://dotnetfiddle.net/5iR3fB .
Alihkan komentar antara Event dan Delegasi dan kode klien yang memanggil / menetapkan nilai untuk didelegasikan untuk memahami perbedaannya
Ini kode inline.
/*
This is working program in Visual Studio. It is not running in fiddler because of infinite loop in code.
This code demonstrates the difference between event and delegate
Event is an delegate reference with two restrictions for increased protection
1. Cannot be invoked directly
2. Cannot assign value to delegate reference directly
Toggle between Event vs Delegate in the code by commenting/un commenting the relevant lines
*/publicclassRoomTemperatureController{privateint _roomTemperature =25;//Default/Starting room Temperatureprivatebool _isAirConditionTurnedOn =false;//Default AC is Offprivatebool _isHeatTurnedOn =false;//Default Heat is Offprivatebool _tempSimulator =false;publicdelegatevoidOnRoomTemperatureChange(int roomTemperature);//OnRoomTemperatureChange is a type of Delegate (Check next line for proof)// public OnRoomTemperatureChange WhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above), publiceventOnRoomTemperatureChangeWhenRoomTemperatureChange;// { get; set; }//Exposing the delegate to outside world, cannot directly expose the delegate (line above), publicRoomTemperatureController(){WhenRoomTemperatureChange+=InternalRoomTemperatuerHandler;}privatevoidInternalRoomTemperatuerHandler(int roomTemp){System.Console.WriteLine("Internal Room Temperature Handler - Mandatory to handle/ Should not be removed by external consumer of ths class: Note, if it is delegate this can be removed, if event cannot be removed");}//User cannot directly asign values to delegate (e.g. roomTempControllerObj.OnRoomTemperatureChange = delegateMethod (System will throw error)publicboolTurnRoomTeperatureSimulator{set{
_tempSimulator =value;if(value){SimulateRoomTemperature();//Turn on Simulator }}get{return _tempSimulator;}}publicvoidTurnAirCondition(bool val){
_isAirConditionTurnedOn = val;
_isHeatTurnedOn =!val;//Binary switch If Heat is ON - AC will turned off automatically (binary)System.Console.WriteLine("Aircondition :"+ _isAirConditionTurnedOn);System.Console.WriteLine("Heat :"+ _isHeatTurnedOn);}publicvoidTurnHeat(bool val){
_isHeatTurnedOn = val;
_isAirConditionTurnedOn =!val;//Binary switch If Heat is ON - AC will turned off automatically (binary)System.Console.WriteLine("Aircondition :"+ _isAirConditionTurnedOn);System.Console.WriteLine("Heat :"+ _isHeatTurnedOn);}publicasyncvoidSimulateRoomTemperature(){while(_tempSimulator){if(_isAirConditionTurnedOn)
_roomTemperature--;//Decrease Room Temperature if AC is turned Onif(_isHeatTurnedOn)
_roomTemperature++;//Decrease Room Temperature if AC is turned OnSystem.Console.WriteLine("Temperature :"+ _roomTemperature);if(WhenRoomTemperatureChange!=null)WhenRoomTemperatureChange(_roomTemperature);System.Threading.Thread.Sleep(500);//Every second Temperature changes based on AC/Heat Status}}}publicclassMySweetHome{RoomTemperatureController roomController =null;publicMySweetHome(){
roomController =newRoomTemperatureController();
roomController.WhenRoomTemperatureChange+=TurnHeatOrACBasedOnTemp;//roomController.WhenRoomTemperatureChange = null; //Setting NULL to delegate reference is possible where as for Event it is not possible.//roomController.WhenRoomTemperatureChange.DynamicInvoke();//Dynamic Invoke is possible for Delgate and not possible with Event
roomController.SimulateRoomTemperature();System.Threading.Thread.Sleep(5000);
roomController.TurnAirCondition(true);
roomController.TurnRoomTeperatureSimulator=true;}publicvoidTurnHeatOrACBasedOnTemp(int temp){if(temp >=30)
roomController.TurnAirCondition(true);if(temp <=15)
roomController.TurnHeat(true);}publicstaticvoidMain(string[]args){MySweetHome home =newMySweetHome();}}
Jika Anda memeriksa Bahasa Intermediate, Anda akan tahu .net compiler convert delegate to class disegel di IL dengan beberapa fungsi built-in, seperti invoke, beginInvoke, endInvoke, dan delegate class yang diwarisi dari kelas lain, mungkin disebut "SystemMulticast". Saya kira Event adalah kelas anak dari Delegasi dengan beberapa properti tambahan.
Perbedaan antara instance acara dan delegasi adalah, Anda tidak dapat menjalankan acara di luar deklarasi. Jika Anda mendeklarasikan acara di kelas A, Anda hanya dapat menjalankan acara ini di kelas A. Jika Anda mendeklarasikan delegasi di Kelas A, Anda dapat menggunakan delegasi ini di mana saja. Saya pikir ini adalah perbedaan utama di antara mereka
Jawaban:
Sebuah acara deklarasi menambahkan lapisan abstraksi dan perlindungan pada delegasi misalnya. Perlindungan ini mencegah klien dari delegasi mengatur ulang delegasi dan daftar doa dan hanya memungkinkan menambah atau menghapus target dari daftar doa.
sumber
Untuk memahami perbedaan Anda dapat melihat 2 contoh ini
Contoh dengan Delegasi (dalam hal ini, Aksi - itu adalah semacam delegasi yang tidak mengembalikan nilai)
Untuk menggunakan delegasi, Anda harus melakukan sesuatu seperti ini:
Kode ini berfungsi dengan baik tetapi Anda dapat memiliki beberapa titik lemah.
Misalnya, jika saya menulis ini:
dengan baris kode terakhir, saya telah menimpa perilaku sebelumnya hanya dengan satu yang hilang
+
(saya telah menggunakan=
alih-alih+=
)Kelemahan lain adalah bahwa setiap kelas yang menggunakan
Animal
kelas Anda dapat meningkatkanRaiseEvent
hanya dengan menyebutnyaanimal.RaiseEvent()
.Untuk menghindari titik-titik lemah ini Anda dapat menggunakan
events
c #.Kelas Hewan Anda akan berubah dengan cara ini:
untuk memanggil acara
Perbedaan:
Catatan:
EventHandler dinyatakan sebagai delegasi berikut:
Dibutuhkan pengirim (tipe objek) dan argumen acara. Pengirim adalah null jika berasal dari metode statis.
Contoh ini, yang menggunakan
EventHandler<ArgsSpecial>
, bisa juga ditulis menggunakanEventHandler
.Rujuk di sini untuk dokumentasi tentang EventHandler
sumber
RaiseEvent
selama metode panggilan memiliki akses ke instanceanimal
dalam kode yang menggunakan acara?animal.Run(this, new ArgsSpecial("Run faster");
?Selain sifat sintaksis dan operasional, ada juga perbedaan semantik.
Delegasi, secara konseptual, templat fungsi; yaitu, mereka menyatakan suatu kontrak yang harus dipatuhi oleh suatu fungsi untuk dipertimbangkan dari "tipe" delegasi.
Acara mewakili ... baik, acara. Mereka dimaksudkan untuk memperingatkan seseorang ketika sesuatu terjadi dan ya, mereka mematuhi definisi delegasi tetapi mereka bukan hal yang sama.
Bahkan jika mereka persis hal yang sama (secara sintaksis dan dalam kode IL) masih akan tetap ada perbedaan semantik. Secara umum saya lebih suka memiliki dua nama yang berbeda untuk dua konsep yang berbeda, bahkan jika mereka diimplementasikan dengan cara yang sama (yang tidak berarti saya suka memiliki kode yang sama dua kali).
sumber
Berikut ini adalah tautan lain yang bagus untuk dirujuk. http://csharpindepth.com/Articles/Chapter2/Events.aspx
Secara singkat, pengambilan dari artikel - Acara adalah enkapsulasi atas delegasi.
Kutipan dari artikel:
sumber
public Delegate
variabel akan mengekspos "data", tetapiDelegate
sejauh pengetahuan saya, OOP tidak pernah menyebut konsep apa pun seperti (itu bukan "objek" atau "pesan") ,.AddXXXHandler
metode Anda sendiri denganprivate Delegate
variabel mungkin merupakan pilihan yang baik. Dalam hal ini Anda dapat memeriksa untuk melihat apakah pawang sudah diatur, dan bereaksi dengan tepat. Ini juga bisa menjadi pengaturan yang baik jika Anda membutuhkan objek yang memegangDelegate
untuk dapat menghapus semua penangan (event
tidak memberi Anda cara untuk melakukan ini).CATATAN: Jika Anda memiliki akses ke C # 5.0 Unleashed , baca "Batasan Penggunaan Utusan Delegasi" di Bab 18 berjudul "Acara" untuk memahami lebih baik perbedaan di antara keduanya.
Selalu membantu saya untuk memiliki contoh yang sederhana dan konkret. Jadi, ini satu untuk komunitas. Pertama saya tunjukkan bagaimana Anda bisa menggunakan delegasi sendirian untuk melakukan apa yang dilakukan Acara untuk kami. Lalu saya tunjukkan bagaimana solusi yang sama akan bekerja dengan contoh
EventHandler
. Dan kemudian saya jelaskan mengapa kita TIDAK ingin melakukan apa yang saya jelaskan pada contoh pertama. Posting ini terinspirasi oleh sebuah artikel oleh John Skeet.Contoh 1: Menggunakan delegasi publik
Misalkan saya memiliki aplikasi WinForms dengan satu kotak drop-down. Drop-down terikat ke
List<Person>
. Di mana Orang memiliki properti Id, Nama, Nama Panggilan, Warna Rambut. Pada formulir utama adalah kontrol pengguna kustom yang menunjukkan properti orang itu. Ketika seseorang memilih seseorang di drop-down label di pembaruan kontrol pengguna untuk menunjukkan properti orang yang dipilih.Inilah cara kerjanya. Kami memiliki tiga file yang membantu kami menyatukan ini:
Berikut adalah kode yang relevan untuk masing-masing kelas:
Inilah kontrol pengguna kami:
Akhirnya kami memiliki kode berikut di Form1.cs kami. Di sini kita Memanggil OnPersonChanged, yang memanggil kode apa saja yang berlangganan delegasi.
Baik. Jadi begitulah cara Anda membuatnya bekerja tanpa menggunakan acara dan hanya menggunakan delegasi . Kami hanya menempatkan delegasi publik ke dalam kelas - Anda dapat membuatnya statis atau tunggal, atau apa pun. Bagus.
NAMUN, NAMUN, NAMUN, kami tidak ingin melakukan apa yang baru saja saya jelaskan di atas. Karena bidang publik buruk karena banyak, banyak alasan. Jadi apa saja pilihan kita? Seperti yang dijelaskan oleh John Skeet, berikut adalah opsi kami:
PersonChangedDel = null
, menghapus semua langganan lainnya. Masalah lain yang tetap ada di sini adalah karena pengguna memiliki akses ke delegasi, mereka dapat meminta target dalam daftar doa - kami tidak ingin pengguna eksternal memiliki akses kapan harus meningkatkan acara kami.Opsi ketiga ini pada dasarnya adalah apa yang diberikan oleh suatu peristiwa kepada kita. Ketika kami mendeklarasikan EventHandler, itu memberi kami akses ke delegasi - tidak secara publik, bukan sebagai properti, tetapi karena hal ini kami sebut acara yang baru saja menambah / menghapus pengakses.
Mari kita lihat seperti apa program yang sama, tetapi sekarang menggunakan Acara alih-alih delegasi publik (Saya juga mengubah Mediator kami menjadi singleton):
Contoh 2: Dengan EventHandler alih-alih delegasi publik
Penengah:
Perhatikan bahwa jika Anda F12 pada EventHandler, itu akan menunjukkan kepada Anda bahwa definisi tersebut hanyalah sebuah delegasi umum dengan objek "pengirim" tambahan:
Kontrol Pengguna:
Akhirnya, inilah kode Form1.cs:
Karena EventHandler ingin dan EventArgs sebagai parameter, saya membuat kelas ini hanya dengan satu properti di dalamnya:
Semoga itu menunjukkan kepada Anda sedikit tentang mengapa kami memiliki acara dan bagaimana mereka berbeda - tetapi secara fungsional sama - seperti delegasi.
sumber
The other problem that remains here is that since the users have access to the delegate, they can invoke the targets in the invocation list -- we don't want external users having access to when to raise our events
. Di versi terbaruMediator
, Anda masih dapat meneleponOnPersonChange
kapan pun Anda memiliki referensi ke singleton. Mungkin Anda harus menyebutkan bahwaMediator
pendekatan itu tidak mencegah perilaku tertentu, dan lebih dekat ke bus peristiwa.Anda juga dapat menggunakan acara dalam deklarasi antarmuka, tidak demikian untuk delegasi.
sumber
Action a { get; set; }
di dalam definisi antarmuka.Benar-benar kesalahpahaman antara acara dan delegasi !!! Delegasi menentukan JENIS (seperti
class
, atauinterface
tidak), sedangkan acara hanya semacam ANGGOTA (seperti bidang, properti, dll). Dan, sama seperti anggota lainnya, acara juga memiliki tipe. Namun, dalam hal acara, jenis acara harus ditentukan oleh delegasi. Misalnya, Anda TIDAK BISA mendeklarasikan peristiwa dari jenis yang ditentukan oleh antarmuka.Sebagai penutup, kita dapat melakukan Pengamatan berikut : jenis acara HARUS ditentukan oleh delegasi . Ini adalah hubungan utama antara acara dan delegasi dan dijelaskan dalam bagian II.18 Mendefinisikan peristiwa dari ECMA-335 (CLI) Partisi Saya ke VI :
Namun, fakta ini TIDAK menyiratkan bahwa suatu peristiwa menggunakan bidang delegasi dukungan . Sebenarnya, suatu peristiwa dapat menggunakan bidang dukungan dari berbagai jenis struktur data pilihan Anda. Jika Anda mengimplementasikan suatu acara secara eksplisit dalam C #, Anda bebas untuk memilih cara Anda menyimpan penangan acara (perhatikan bahwa penangan acara adalah contoh dari jenis acara , yang pada gilirannya adalah wajib merupakan jenis delegasi --- dari Pengamatan sebelumnya) ). Tetapi, Anda bisa menyimpan event handler tersebut (yang merupakan contoh delegasi) dalam struktur data seperti a
List
atau aDictionary
atau yang lain, atau bahkan dalam bidang delegasi pendukung. Tapi jangan lupa bahwa TIDAK wajib Anda menggunakan bidang delegasi.sumber
Peristiwa di .net adalah kombinasi yang ditunjuk dari metode Tambahkan dan metode Hapus, yang keduanya mengharapkan beberapa jenis delegasi tertentu. Baik C # maupun vb.net dapat membuat kode secara otomatis untuk metode tambah dan hapus yang akan menentukan delegasi untuk menahan langganan acara, dan menambah / menghapus delegasi yang diteruskan ke / dari delegasi berlangganan tersebut. VB.net juga akan menghasilkan kode secara otomatis (dengan pernyataan RaiseEvent) untuk memohon daftar langganan jika dan hanya jika tidak kosong; untuk beberapa alasan, C # tidak menghasilkan yang terakhir.
Perhatikan bahwa walaupun umum untuk mengelola langganan acara menggunakan delegasi multicast, itu bukan satu-satunya cara untuk melakukannya. Dari perspektif publik, calon pelanggan acara perlu tahu cara memberi tahu objek bahwa ia ingin menerima acara, tetapi tidak perlu tahu mekanisme apa yang akan digunakan penerbit untuk mengangkat acara tersebut. Perhatikan juga bahwa sementara siapa pun yang mendefinisikan struktur data acara di .net tampaknya berpikir harus ada sarana publik untuk meningkatkannya, baik C # maupun vb.net tidak menggunakan fitur itu.
sumber
Untuk mendefinisikan tentang acara dengan cara sederhana:
Acara adalah REFERENSI untuk seorang delegasi dengan dua batasan
Di atas dua adalah titik lemah untuk delegasi dan ditangani jika terjadi. Contoh kode lengkap untuk menunjukkan perbedaan dalam fiddler ada di sini https://dotnetfiddle.net/5iR3fB .
Alihkan komentar antara Event dan Delegasi dan kode klien yang memanggil / menetapkan nilai untuk didelegasikan untuk memahami perbedaannya
Ini kode inline.
sumber
Delegasi adalah pointer fungsi tipe-aman. Acara adalah implementasi dari pola desain penerbit-pelanggan menggunakan delegasi.
sumber
Jika Anda memeriksa Bahasa Intermediate, Anda akan tahu .net compiler convert delegate to class disegel di IL dengan beberapa fungsi built-in, seperti invoke, beginInvoke, endInvoke, dan delegate class yang diwarisi dari kelas lain, mungkin disebut "SystemMulticast". Saya kira Event adalah kelas anak dari Delegasi dengan beberapa properti tambahan.
Perbedaan antara instance acara dan delegasi adalah, Anda tidak dapat menjalankan acara di luar deklarasi. Jika Anda mendeklarasikan acara di kelas A, Anda hanya dapat menjalankan acara ini di kelas A. Jika Anda mendeklarasikan delegasi di Kelas A, Anda dapat menggunakan delegasi ini di mana saja. Saya pikir ini adalah perbedaan utama di antara mereka
sumber