Delegasi dan Acara di C #

Terjemahan artikel disiapkan khusus untuk siswa kursus "Pengembang C #" .




Apa acara di C #?


Suatu acara dapat digunakan untuk memberikan pemberitahuan. Anda dapat berlangganan ke acara tersebut jika Anda membutuhkan pemberitahuan ini. Anda juga dapat membuat acara sendiri yang akan memberi tahu Anda bahwa sesuatu yang menarik perhatian Anda telah terjadi. .NET Framework menawarkan tipe bawaan yang dapat Anda gunakan untuk membuat acara. Menggunakan delegasi, ekspresi lambda, dan metode anonim, Anda dapat membuat dan menggunakan acara dengan nyaman.

Memahami Delegasi dalam C #


Di C #, delegasi membentuk blok bangunan dasar untuk acara. Delegasi adalah tipe yang mendefinisikan tanda tangan suatu metode. Misalnya, dalam C ++, ini bisa dilakukan dengan menggunakan pointer fungsi. Di C #, Anda bisa membuat instance delegasi yang menunjuk ke metode lain. Anda dapat memanggil metode ini melalui instance delegasi.

Berikut ini adalah contoh menyatakan delegasi dan memanggil metode melalui itu.

Menggunakan delegasi dalam C #


}class Program { public delegate double MathDelegate(double value1, double value2); public static double Add(double value1, double value2) { return value1 + value2; } public static double Subtract(double value1, double value2) { return value1 - value2; } Console.ReadLine(); public static void Main() { MathDelegate mathDelegate = Add; var result = mathDelegate(5, 2); Console.WriteLine(result); // : 7 mathDelegate = Subtract; result = mathDelegate(5, 2); Console.WriteLine(result); // : 3 } 

Seperti yang Anda lihat, kami menggunakan kata kunci delegasi untuk memberi tahu kompiler bahwa kami sedang membuat tipe delegasi.

Sangat mudah untuk membuat instance delegasi bersama dengan pembuatan otomatis tipe delegasi baru.

Anda juga dapat menggunakan kata kunci baru untuk membuat delegasi.

MathDelegate mathDelegate = new MathDelegate(Add) ;

Delegasi yang dipakai adalah objek; Anda juga dapat menggunakannya dan memberikan argumen untuk metode lain.

Delegasi Multicast di C #


Fitur hebat lain dari delegasi adalah bahwa Anda dapat menggabungkan mereka bersama. Ini disebut multicasting. Anda dapat menggunakan operator + atau + = untuk menambahkan metode lain ke daftar panggilan dari instance delegasi yang ada. Demikian pula, Anda juga dapat menghapus metode dari daftar panggilan menggunakan operator penetapan penurunan (- atau - =). Fitur ini berfungsi sebagai dasar untuk acara di C #. Berikut ini adalah contoh delegasi multicast.

 class Program { static void Hello(string s) { Console.WriteLine(" Hello, {0}!", s); } static void Goodbye(string s) { Console.WriteLine(" Goodbye, {0}!", s); } delegate void Del(string s); static void Main() { Del a, b, c, d; //   a    Hello: a = Hello; //   b    Goodbye: b = Goodbye; //    a  b - c: c = a + b; //  a    c,   d,       Goodbye: d = c - a; Console.WriteLine("Invoking delegate a:"); a("A"); Console.WriteLine("Invoking delegate b:"); b("B"); Console.WriteLine("Invoking delegate c:"); c("C"); Console.WriteLine("Invoking delegate d:"); d("D"); /* : Invoking delegate a: Hello, A! Invoking delegate b: Goodbye, B! Invoking delegate c: Hello, C! Goodbye, C! Invoking delegate d: Goodbye, D! */ Console.ReadLine(); } } 

Ini dimungkinkan karena delegasi mewarisi dari kelas System.MulticastDelegate , yang pada gilirannya mewarisi dari System.Delegate . Anda dapat menggunakan anggota yang ditentukan dalam kelas dasar ini untuk delegasi Anda.

Misalnya, untuk mengetahui berapa banyak metode yang akan dipanggil oleh delegasi multicast, Anda dapat menggunakan kode berikut:

 int invocationCount = d.GetInvocationList().GetLength(0); 

Kovarian dan contravariance dalam C #


Saat Anda menetapkan metode untuk delegasi, tanda tangan metode tidak harus sama persis dengan delegasi. Ini disebut kovarians dan contravariance. Kovarian memungkinkan metode untuk memiliki tipe pengembalian yang lebih diturunkan dari yang didefinisikan dalam delegasi. Contravariance memungkinkan metode dengan tipe-tipe parameter yang lebih sedikit diturunkan daripada tipe-tipe dalam delegasi.

Delegasikan Kovarian


Berikut ini adalah contoh kovarians,

 class Program { public delegate TextWriter CovarianceDel(); public static StreamWriter MethodStream() { return null; } public static StringWriter MethodString() { return null; } static void Main() { CovarianceDel del; del = MethodStream; del = MethodString; Console.ReadLine(); } } 

Karena StreamWriter dan StringWriter mewarisi dari TextWriter , Anda dapat menggunakan CovarianceDel dengan kedua metode.

Kontravarians dalam delegasi


Berikut ini adalah contoh dari contravariance.

 class Program { public static void DoSomething(TextWriter textWriter) { } public delegate void ContravarianceDel(StreamWriter streamWriter); static void Main() { ContravarianceDel del = DoSomething; Console.ReadLine(); } } 

Karena metode DoSomething dapat bekerja dengan TextWriter , tentu saja dapat bekerja dengan StreamWriter . Karena contravariance, Anda dapat memanggil delegasi dan meneruskan turunan StreamWriter ke metode DoSomething .

Anda dapat mempelajari lebih lanjut tentang konsep ini di sini .

Ekspresi Lambda dalam C #


Terkadang seluruh tanda tangan metode mungkin memerlukan lebih banyak kode daripada isi metode itu sendiri. Ada juga situasi di mana Anda perlu membuat seluruh metode hanya untuk menggunakannya sebagai delegasi.

Untuk kasus ini, Microsoft telah menambahkan beberapa fitur baru di C #, seperti metode anonim di 2.0. Di C # 3.0, segalanya menjadi lebih baik ketika ekspresi lambda ditambahkan. Ekspresi Lambda adalah cara yang disukai saat menulis kode baru.

Berikut ini adalah contoh sintaks lambda terbaru.

 class Program { public delegate double MathDelegate(double value1, double value2); public static void Main() { MathDelegate mathDelegate = (x,y) => x + y; var result = mathDelegate(5, 2); Console.WriteLine(result); // : 7 mathDelegate = (x, y) => x - y; ; result = mathDelegate(5, 2); Console.WriteLine(result); // : 3 Console.ReadLine(); } } 

Untuk membaca kode ini, Anda perlu menggunakan kata "mengikuti" dalam konteks sintaks lambda khusus. Misalnya, ekspresi lambda pertama dalam contoh di atas bertuliskan "x dan y ikuti penambahan x dan y".

Fungsi lambda tidak memiliki nama tertentu, tidak seperti metode. Karena itu, lambda disebut fungsi anonim. Anda juga tidak perlu secara eksplisit menentukan jenis nilai pengembalian. Kompilator menganggapnya secara otomatis dari lambda Anda. Dan dalam kasus contoh di atas, tipe parameter x dan y juga tidak ditentukan secara eksplisit.

Anda dapat membuat lambda yang menjangkau beberapa operator. Anda dapat melakukan ini dengan menambahkan kurung kurawal di sekitar pernyataan yang membentuk lambda, seperti yang ditunjukkan pada contoh di bawah ini.

 MathDelegate mathDelegate = (x,y) => { Console.WriteLine("Add"); return x + y; }; 

Terkadang pengumuman delegasi untuk suatu acara tampak agak rumit. Karena itu, .NET Framework memiliki beberapa tipe delegasi bawaan yang dapat Anda gunakan saat mendeklarasikan delegasi. Dalam contoh MathDelegate, Anda menggunakan delegasi berikut:

 public delegate double MathDelegate(double value1, double value2); 

Anda dapat mengganti delegasi ini dengan salah satu tipe Func <int, int, int> , yaitu Func <int, int, int> .

seperti itu

 class Program { public static void Main() { Func<int, int, int> mathDelegate = (x,y) => { Console.WriteLine("Add"); return x + y; }; var result = mathDelegate(5, 2); Console.WriteLine(result); // : 7 mathDelegate = (x, y) => x - y; ; result = mathDelegate(5, 2); Console.WriteLine(result); // : 3 Console.ReadLine(); } } 

Jenis fungsi <...> dapat ditemukan di System namespace. Mereka mewakili delegasi yang mengembalikan tipe dan mengambil dari 0 hingga 16 parameter. Semua tipe ini diwarisi dari System.MulticaseDelegate sehingga Anda dapat menambahkan beberapa metode ke daftar panggilan.

Jika Anda membutuhkan tipe delegasi yang tidak mengembalikan nilai, Anda bisa menggunakan tipe System.Action. Mereka juga dapat mengambil dari 0 hingga 16 parameter, tetapi tidak mengembalikan nilai.

Ini adalah contoh penggunaan tipe Action,

 class Program { public static void Main() { Action<int, int> mathDelegate = (x,y) => { Console.WriteLine(x + y); }; mathDelegate(5, 2); // : 7 mathDelegate = (x, y) => Console.WriteLine(x - y) ; mathDelegate(5, 2); // : 3 Console.ReadLine(); } } 

Anda dapat mempelajari lebih lanjut tentang delegasi bawaan .NET di sini .

Hal menjadi rumit ketika fungsi lambda Anda mulai merujuk ke variabel yang dideklarasikan di luar ekspresi lambda atau ini. Biasanya, ketika kontrol meninggalkan ruang lingkup variabel, variabel menjadi tidak valid. Tetapi bagaimana jika delegasi mengacu pada variabel lokal. Untuk memperbaikinya, kompiler menghasilkan kode yang memperpanjang umur variabel yang ditangkap, setidaknya selama hidup delegasi yang paling lama hidup. Ini disebut penutupan.

Anda dapat mempelajari lebih lanjut tentang penutupan di sini .

Acara di C #


Pertimbangkan pola pengembangan populer - penerbit-pelanggan (pub / sub). Anda dapat berlangganan ke suatu acara, dan kemudian Anda akan diberi tahu ketika penerbit acara memulai acara baru. Sistem ini digunakan untuk membangun komunikasi yang lemah antar komponen dalam suatu aplikasi.

Delegasi membentuk dasar untuk sistem acara di C #.

Suatu acara adalah jenis delegasi khusus yang memfasilitasi pemrograman berorientasi acara. Acara adalah anggota kelas yang tidak bisa dipanggil di luar kelas, terlepas dari penentu akses. Jadi, misalnya, suatu peristiwa yang dinyatakan sebagai publik akan memungkinkan kelas lain menggunakan + = dan - = untuk acara ini, tetapi memicu suatu peristiwa (yaitu, memanggil delegasi) hanya diperbolehkan di kelas yang berisi acara tersebut. Mari kita lihat sebuah contoh,

 // -  Pub public class Pub { // OnChange    callback-  public event Action OnChange = delegate { }; public void Raise() { // OnChange OnChange(); } } 

Kemudian, metode di kelas lain dapat berlangganan acara dengan menambahkan salah satu metode tersebut ke delegasi acara:

Berikut ini adalah contoh yang menunjukkan bagaimana suatu kelas dapat menyediakan delegasi terbuka dan menghasilkan suatu acara.

 class Program { static void Main(string[] args) { //   pub Pub p = new Pub(); //  Subscriber 1   OnChange p.OnChange += () => Console.WriteLine("Subscriber 1!"); //  Subscriber 2   OnChange p.OnChange += () => Console.WriteLine("Subscriber 2!"); //  p.Raise(); //   Raise()   callback-     Console.WriteLine("Press enter to terminate!"); Console.ReadLine(); } } 

Bahkan jika acara tersebut dinyatakan sebagai public , itu tidak dapat dipicu secara langsung di mana pun kecuali di kelas di mana ia berada.

Menggunakan kata kunci event , kompiler melindungi bidang kami dari akses yang tidak diinginkan.

Dan juga

Itu tidak mengizinkan penggunaan = (penugasan delegasi langsung). Karenanya, kode Anda sekarang dilindungi dari risiko menghapus pelanggan sebelumnya dengan menggunakan = alih-alih + =.

Selain itu, Anda mungkin memperhatikan sintaks inisialisasi bidang OnChange khusus untuk delegasi kosong, seperti delegate { } . Ini memastikan bahwa bidang OnChange kami tidak pernah nol. Oleh karena itu, kami dapat menghapus cek nol sebelum memanggil acara jika tidak ada anggota kelas lain yang membatalkannya.

Ketika Anda menjalankan program di atas, kode Anda membuat instance baru Pub, berlangganan acara dengan dua cara berbeda, dan menghasilkan acara dengan memanggil p.Raise. Kelas Pub sama sekali tidak mengetahui pelanggan mana pun. Itu hanya menghasilkan suatu acara.

Anda juga dapat membaca artikel saya, Pola Desain C # Penerbit-Pelanggan, untuk pemahaman yang lebih dalam tentang konsep ini.

Nah, itu saja untuk saat ini. Saya harap Anda mendapatkan idenya. Terima kasih sudah membaca posting. Harap beri tahu saya jika ada kesalahan atau perubahan yang diperlukan dalam komentar di bawah. Terima kasih sebelumnya!

Tautan yang bermanfaat


www.c-sharpcorner.com/blogs/c-sharp-generic-delegates-func-action-and-predicate
docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance
https://web.archive.org/web/20150707082707/http://diditwith.net/PermaLink,guid,235646ae-3476-4893-899d-105e4d48c25b.aspx

Source: https://habr.com/ru/post/id472094/


All Articles