Perbedaan antara acara dan delegasi serta aplikasinya masing-masing [tutup]

107

Saya tidak melihat keuntungan menggunakan acara dibandingkan delegasi, selain menjadi gula sintaksis. Mungkin saya salah paham, tapi sepertinya acara itu hanya placeholder untuk delegasi.

Maukah Anda menjelaskan kepada saya perbedaannya dan kapan harus menggunakan yang mana? Apa kelebihan dan kekurangannya? Kode kami berakar kuat dengan peristiwa, dan saya ingin membukanya.

Kapan Anda akan menggunakan delegasi untuk acara dan sebaliknya? Sebutkan pengalaman dunia nyata Anda dengan keduanya, misalnya di kode produksi.

halfer
sumber
Ya membungkus kepala saya di sekitar perbedaan itu sangat sulit, mereka terlihat sama dan tampaknya melakukan hal yang sama pada pandangan pertama
Robert Gould
1
Lihat juga pertanyaan ini .
Dimitri C.
1
Perbedaan antara dua acara dan delegasi adalah masalah fakta, bukan opini. Pertanyaan menanyakan aplikasi masing-masing karena mereka menggambarkan perbedaan dalam masalah yang dipecahkan oleh teknologi. Ini juga bukan masalah opini karena tidak ada yang menanyakan mana yang terbaik. Tidak ada bagian dari pertanyaan ini yang merupakan masalah opini, dan pernyataan ini juga bukan opini. Menurutku. Apakah Anda mendapatkan lencana Anda?
Peter Wone

Jawaban:

49

Dari sudut pandang teknis, jawaban lain telah menjawab perbedaan tersebut.

Dari perspektif semantik, peristiwa adalah tindakan yang dimunculkan oleh suatu objek ketika kondisi tertentu terpenuhi. Misalnya, kelas Saham saya memiliki properti yang disebut Limit, dan itu menimbulkan peristiwa ketika harga saham mencapai Limit. Notifikasi ini dilakukan melalui sebuah acara. Apakah ada orang yang benar-benar peduli tentang acara ini dan berlangganan ke dalamnya, itu bukan urusan kelas pemilik.

Delegasi adalah istilah yang lebih umum untuk menggambarkan konstruksi yang mirip dengan pointer dalam istilah C / C ++. Semua delegasi di .Net adalah delegasi multicast. Dari perspektif semantik, umumnya digunakan sebagai semacam masukan. Secara khusus, ini adalah cara sempurna untuk menerapkan Pola Strategi . Sebagai contoh, jika saya ingin mengurutkan daftar objek, saya dapat memberikan strategi pembanding untuk metode untuk memberitahu implementasi bagaimana membandingkan dua objek.

Saya telah menggunakan dua metode dalam kode produksi. Banyak objek data saya memberi tahu saat properti tertentu terpenuhi. Contoh paling dasar, setiap kali properti berubah, acara PropertyChanged dimunculkan (lihat antarmuka INotifyPropertyChanged). Saya telah menggunakan delegasi dalam kode untuk memberikan strategi berbeda untuk mengubah objek tertentu menjadi string. Contoh khusus ini adalah daftar implementasi ToString () yang dimuliakan untuk tipe objek tertentu untuk ditampilkan kepada pengguna.

Szymon Rozga
sumber
4
Mungkin saya melewatkan sesuatu, tetapi bukankah Event Handler adalah tipe delegasi?
Powerlord
1
Jawaban saya menjawab pertanyaan Sunting # 1 dan # 2; perbedaan dari perspektif penggunaan. Untuk keperluan diskusi ini, mereka berbeda, meskipun dari sudut pandang teknis, Anda benar. Lihatlah jawaban lain untuk perbedaan teknis.
Szymon Rozga
3
"Semua delegasi di .Net adalah delegasi multicast"? Bahkan delegasi yang mengembalikan nilai?
Qwertie
5
Iya. Untuk riwayat, lihat msdn.microsoft.com/en-us/magazine/cc301816.aspx . Lihat: msdn.microsoft.com/en-us/library/system.delegate.aspx . Jika mereka mengembalikan nilai, nilai yang dikembalikan adalah evaluasi delegasi terakhir dalam rantai.
Szymon Rozga
delegasi adalah tipe referensi yang menunjuk ke event handler yang didefinisikan dalam kelas pelanggan. Dengan kata lain, delegasi digunakan sebagai penghubung antara acara (di penerbit) dan pengendali acara yang ditentukan di pelanggan. Dalam sebuah aplikasi, akan ada banyak pelanggan yang perlu mendengarkan suatu acara, dan dalam skenario seperti itu, delegasi menawarkan kepada kami cara yang efisien untuk menghubungkan penerbit dan pelanggan.
josepainumkal
55

Kata kunci eventadalah pengubah cakupan untuk delegasi multicast. Perbedaan praktis antara ini dan hanya mendeklarasikan delegasi multicast adalah sebagai berikut:

  • Anda dapat menggunakan eventdi antarmuka.
  • Akses pemanggilan ke delegasi multicast terbatas pada kelas yang mendeklarasikan. Perilakunya seolah-olah delegasi itu pribadi untuk doa. Untuk tujuan penugasan, akses ditentukan oleh pengubah akses eksplisit (misalnya public event).

Sesuai minat, Anda dapat menerapkan +dan -ke delegasi multicast, dan ini adalah dasar sintaks +=dan -=untuk penugasan kombinasi delegasi ke acara. Ketiga cuplikan ini setara:

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = B + C;

Contoh dua, menggambarkan penugasan langsung dan penugasan kombinasi.

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = B;
A += C;

Contoh tiga: sintaks yang lebih familiar. Anda mungkin terbiasa dengan tugas null untuk menghapus semua penangan.

B = new EventHandler(this.MethodB);
C = new EventHandler(this.MethodC);
A = null;
A += B;
A += C;

Seperti properti, peristiwa memiliki sintaks lengkap yang tidak pernah digunakan siapa pun. Ini:

class myExample 
{
  internal EventHandler eh;

  public event EventHandler OnSubmit 
  { 
    add 
    {
      eh = Delegate.Combine(eh, value) as EventHandler;
    }
    remove
    {
      eh = Delegate.Remove(eh, value) as EventHandler;
    }
  }

  ...
}

... melakukan hal yang sama persis seperti ini:

class myExample 
{
  public event EventHandler OnSubmit;
}

Metode tambah dan hapus lebih mencolok dalam sintaks yang agak kaku yang digunakan VB.NET (tidak ada operator yang kelebihan beban).

Peter Wone
sumber
6
+ untuk "Akses pemanggilan ke delegasi multicast terbatas pada kelas mendeklarasikan" - bagi saya adalah titik perbedaan utama antara delegasi dan acara.
RichardOD
2
Perbedaan penting lainnya (disebutkan oleh itowlson di bawah) adalah bahwa seseorang tidak dapat menghentikan langganan semua penangan acara dengan menetapkan ke suatu acara, tetapi mereka dapat melakukannya dengan seorang delegasi. (Ngomong-ngomong, jawaban Anda adalah jawaban yang paling berguna bagi saya dari semua ini).
Roman Starkov
4
Berguna seperti Google dan stackoverflow, semua ini dan lebih banyak lagi tersedia dalam detail yang mematikan dalam spesifikasi bahasa C #, tersedia untuk umum tanpa biaya dari Microsoft. Saya tahu bahwa secara
sepintas lalu
12

Acara adalah gula sintaksis. Mereka enak. Ketika saya melihat sebuah acara, saya tahu apa yang harus saya lakukan. Ketika saya melihat seorang delegasi, saya tidak begitu yakin.

Menggabungkan acara dengan antarmuka (lebih banyak gula) membuat camilan yang menggugah selera. Delegasi dan kelas abstrak virtual murni kurang menarik.

Sean
sumber
begitulah cara saya melihatnya juga. Saya ingin penjelasan yang lebih dalam dan lebih manis :)
13
Terlalu banyak gula membuat seseorang gemuk, namun ... = P
Erik Forbes
5

Peristiwa ditandai seperti itu di metadata. Hal ini memungkinkan hal-hal seperti desainer Windows Forms atau ASP.NET untuk membedakan kejadian dari properti tipe delegasi, dan memberikan dukungan yang sesuai untuk mereka (secara khusus menunjukkannya pada tab Kejadian pada jendela Properti).

Perbedaan lain dari properti tipe delegasi adalah bahwa pengguna hanya bisa menambah dan menghapus pengendali event, sedangkan dengan properti tipe delegasi mereka bisa menyetel nilainya:

someObj.SomeCallback = MyCallback;  // okay, replaces any existing callback
someObj.SomeEvent = MyHandler;  // not okay, must use += instead

Ini membantu memisahkan pelanggan acara: Saya dapat menambahkan penangan saya ke acara, dan Anda dapat menambahkan penangan ke acara yang sama, dan Anda tidak akan menimpa penangan saya secara tidak sengaja.

itowlson
sumber
4

Meskipun acara biasanya diimplementasikan dengan delegasi multicast, tidak ada persyaratan bahwa acara tersebut digunakan dengan cara seperti itu. Jika kelas mengekspos acara, itu berarti kelas tersebut mengekspos dua metode. Artinya, pada dasarnya:

  1. Ini seorang delegasi. Tolong panggil ketika sesuatu yang menarik terjadi.
  2. Ini seorang delegasi. Anda harus menghancurkan semua referensi ke sana secepat mungkin (dan tidak lagi menyebutnya).

Cara paling umum bagi kelas untuk menangani peristiwa yang dipaparkannya adalah dengan mendefinisikan delegasi multicast, dan menambahkan / menghapus setiap delegasi yang diteruskan ke metode di atas tetapi tidak ada persyaratan bahwa mereka bekerja seperti itu. Sayangnya, arsitektur acara gagal melakukan beberapa hal yang akan membuat pendekatan alternatif jauh lebih bersih (misalnya, meminta metode berlangganan mengembalikan MethodInvoker, yang akan disimpan oleh pelanggan; untuk berhenti berlangganan acara, cukup panggil metode yang dikembalikan) sehingga delegasi multicast sejauh ini merupakan pendekatan yang paling umum.

supercat
sumber
4

untuk memahami perbedaannya Anda dapat melihat 2 contoh ini

Contoh dengan Delegasi (Tindakan dalam hal ini adalah jenis delegasi yang tidak mengembalikan nilai)

public class Animal
{
    public Action Run {get; set;}

    public void RaiseEvent()
    {
        if (Run != null)
        {
            Run();
        }
    }
}

untuk menggunakan delegasi, Anda harus melakukan sesuatu seperti ini

Animale animal= new Animal();
animal.Run += () => Console.WriteLine("I'm running");
animal.Run += () => Console.WriteLine("I'm still running") ;
animal.RaiseEvent();

kode ini berfungsi dengan baik tetapi Anda mungkin 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 yang saya timpa perilaku sebelumnya hanya dengan satu yang hilang +(saya gunakan +sebagai gantinya +=)

Titik lemah lainnya adalah bahwa setiap kelas yang menggunakan Animalkelas Anda dapat menaikkan RaiseEventpanggilannya saja animal.RaiseEvent().

Untuk menghindari titik lemah ini Anda dapat menggunakan eventsdi c #.

Kelas Hewan Anda akan berubah dengan cara ini

public class ArgsSpecial :EventArgs
   {
        public ArgsSpecial (string val)
        {
            Operation=val;
        }

        public string Operation {get; set;}
   } 



 public class Animal
    {
       public event EventHandler<ArgsSpecial> Run = delegate{} //empty delegate. In this way you are sure that value is always != null because no one outside of the class can change it

       public void RaiseEvent()
       {  
          Run(this, new ArgsSpecial("Run faster"));
       }
    }

untuk memanggil acara

 Animale animal= new Animal();
 animal.Run += (sender, e) => Console.WriteLine("I'm running. My value is {0}", e.Operation);
 animal.RaiseEvent();

Perbedaan:

  1. Anda tidak menggunakan properti publik tetapi bidang publik (dengan kejadian, kompilator melindungi bidang Anda dari akses yang tidak diinginkan)
  2. Acara tidak bisa langsung ditugaskan. Dalam hal ini Anda tidak dapat melakukan kesalahan sebelumnya yang telah saya tunjukkan dengan menimpa perilaku.
  3. Tidak ada orang di luar kelas Anda yang dapat mengangkat acara.
  4. Peristiwa dapat dimasukkan dalam deklarasi antarmuka, sedangkan bidang tidak bisa

catatan

EventHandler dideklarasikan sebagai delegasi berikut:

public delegate void EventHandler (object sender, EventArgs e)

itu membutuhkan pengirim (tipe Object) dan argumen event. Pengirim bernilai null jika berasal dari metode statis.

Anda juga dapat menggunakan EventHAndlercontoh yang menggunakan iniEventHandler<ArgsSpecial>

lihat di sini untuk dokumentasi tentang EventHandler

faby
sumber
3

Sunting # 1 Kapan Anda akan menggunakan delegasi dalam acara dan vs. versa? Sebutkan pengalaman dunia nyata Anda dengan keduanya, misalnya di kode produksi.

Ketika saya mendesain API saya sendiri, saya mendefinisikan delegasi yang diteruskan sebagai parameter ke metode, atau ke konstruktor kelas:

  • Sehingga sebuah metode dapat mengimplementasikan pola 'metode template' sederhana (misalnya delegasi Predicatedan Actionditeruskan ke kelas koleksi generik .Net)
  • Atau agar kelas dapat melakukan 'callback' (biasanya callback ke metode kelas yang membuatnya).

Ini delegasi umumnya non-opsional pada saat run-time (yaitu tidak harus null).

Saya cenderung tidak menggunakan acara; tetapi di mana saya menggunakan peristiwa, saya menggunakannya untuk secara opsional memberi sinyal peristiwa ke nol, satu, atau lebih klien yang mungkin tertarik, yaitu ketika masuk akal bahwa kelas (misalnya System.Windows.Formkelas) harus ada dan dijalankan apakah ada klien atau tidak menambahkan event handler ke eventnya (misal event form 'mouse down' ada, tapi opsional apakah ada klien eksternal yang tertarik untuk menginstal event handler ke event itu).

ChrisW
sumber
2

Meskipun saya tidak punya alasan teknis untuk itu, saya menggunakan kejadian dalam kode gaya UI, dengan kata lain, di tingkat kode yang lebih tinggi, dan menggunakan delegasi untuk logika yang terletak lebih dalam di kode. Seperti yang saya katakan Anda dapat menggunakan keduanya, tetapi saya menemukan pola penggunaan ini terdengar logis, jika tidak ada yang lain, ini membantu mendokumentasikan jenis callback dan hierarki mereka juga.


Sunting: Saya pikir perbedaan dalam pola penggunaan yang saya miliki adalah bahwa, saya merasa sangat dapat diterima untuk mengabaikan acara, mereka adalah kait / rintisan, jika Anda perlu tahu tentang acara tersebut, dengarkan mereka, jika Anda tidak peduli acara tersebut abaikan saja. Itu sebabnya saya menggunakannya untuk UI, jenis gaya acara Javascript / Browser. Namun ketika saya memiliki delegasi, saya berharap BENAR-BENAR mengharapkan seseorang untuk menangani tugas delegasi, dan memberikan pengecualian jika tidak ditangani.

Robert Gould
sumber
Maukah Anda menguraikannya karena saya juga menggunakan acara di UI? Contoh yang baik sudah cukup .... terima kasih
1

Perbedaan antara acara dan delegasi jauh lebih kecil daripada yang saya kira. Saya baru saja memposting video YouTube yang sangat pendek tentang subjek: https://www.youtube.com/watch?v=el-kKK-7SBU

Semoga ini membantu!

Pontus Wittenmark
sumber
2
Selamat datang di Stack Overflow! Meskipun ini secara teoritis dapat menjawab pertanyaan, akan lebih baik jika menyertakan bagian penting dari jawaban di sini, dan menyediakan tautan untuk referensi.
GhostCat
1

Jika kita hanya menggunakan delegasi di tempat Acara maka pelanggan memiliki kesempatan untuk mengkloning (), memanggil () delegasi itu sendiri seperti yang ditunjukkan di bawah ini pada gambar. Mana yang tidak benar.

masukkan deskripsi gambar di sini

Itulah perbedaan utama antara acara dan delegasi. pelanggan hanya memiliki satu hak yaitu mendengarkan acara

Kelas ConsoleLog berlangganan peristiwa log melalui EventLogHandler

public class ConsoleLog
{
    public ConsoleLog(Operation operation)
    {
        operation.EventLogHandler += print;
    }

    public void print(string str)
    {
        Console.WriteLine("write on console : " + str);
    }
}

Kelas FileLog berlangganan peristiwa log melalui EventLogHandler

public class FileLog
{
    public FileLog(Operation operation)
    {
        operation.EventLogHandler += print;
    }

    public void print(string str)
    {
        Console.WriteLine("write in File : " + str);
    }
}

Kelas operasi menerbitkan peristiwa log

public delegate void logDelegate(string str);
public class Operation
{
    public event logDelegate EventLogHandler;
    public Operation()
    {
        new FileLog(this);
        new ConsoleLog(this);
    }

    public void DoWork()
    {
        EventLogHandler.Invoke("somthing is working");
    }
}
Narottam Goyal
sumber