Bagikan melalui


System.Delegate dan delegate kata kunci

Sebelumnya

Artikel ini membahas kelas di .NET yang mendukung delegasi, dan bagaimana peta tersebut ke delegate kata kunci.

Menentukan tipe delegasi

Mari kita mulai dengan kata kunci 'delegasi', karena itulah yang akan Anda gunakan saat Anda bekerja dengan delegasi. Kode yang dihasilkan pengkompilasi saat Anda menggunakan delegate kata kunci akan memetakan ke panggilan metode yang memanggil anggota kelas Delegate dan MulticastDelegate.

Anda menentukan jenis delegasi menggunakan sintaks yang mirip dengan menentukan tanda tangan metode. Anda cukup menambahkan delegate kata kunci ke definisi.

Mari kita terus menggunakan metode List.Sort() sebagai contoh kita. Langkah pertama adalah membuat jenis untuk delegasi perbandingan:

// From the .NET Core library

// Define the delegate type:
public delegate int Comparison<in T>(T left, T right);

Pengkompilasi menghasilkan kelas, yang berasal dari System.Delegate yang cocok dengan tanda tangan yang digunakan (dalam hal ini, metode yang mengembalikan bilangan bulat, dan memiliki dua argumen). Jenis delegasi tersebut adalah Comparison. Jenis Comparison delegasi adalah jenis generik. Untuk detail tentang generik lihat di sini.

Perhatikan bahwa sintaks mungkin muncul seolah-olah mendeklarasikan variabel, tetapi sebenarnya mendeklarasikan jenis. Anda dapat menentukan jenis delegasi di dalam kelas, langsung di dalam ruang nama, atau bahkan di ruang nama global.

Catatan

Mendeklarasikan jenis delegasi (atau jenis lain) langsung di ruang nama global tidak disarankan.

Kompiler juga menghasilkan add and remove handler untuk tipe baru ini sehingga klien kelas ini dapat menambahkan dan menghapus metode dari daftar pemanggilan instans. Kompiler akan menegakkan bahwa tanda tangan metode yang ditambahkan atau dihapus cocok dengan tanda tangan yang digunakan saat mendeklarasikan metode.

Mendeklarasikan contoh delegasi

Setelah menentukan delegasi, Anda dapat membuat instance jenis tersebut. Seperti semua variabel di C#, Anda tidak dapat mendeklarasikan instans delegasi secara langsung di ruang nama, atau di ruang nama global.

// inside a class definition:

// Declare an instance of that type:
public Comparison<T> comparator;

Jenis variabel adalah Comparison<T>, jenis delegasi yang ditentukan sebelumnya. Nama variabelnya adalah comparator.

Cuplikan kode di atas mendeklarasikan variabel anggota di dalam kelas. Anda juga dapat mendeklarasikan variabel delegasi yang merupakan variabel lokal, atau argumen ke metode.

Memanggil delegasi

Anda meminta metode yang ada dalam daftar pemanggilan delegasi dengan memanggil delegasi tersebut. Di dalam metode Sort(), kode akan memanggil metode perbandingan untuk menentukan urutan mana untuk menempatkan objek:

int result = comparator(left, right);

Pada baris di atas, kode memanggil metode yang dilampirkan ke delegasi. Anda memperlakukan variabel sebagai nama metode, dan memanggilnya menggunakan sintaks panggilan metode normal.

Baris kode itu membuat asumsi yang tidak aman: Tidak ada jaminan bahwa target telah ditambahkan ke delegasi. Jika tidak ada target yang terpasang, garis di atas akan menyebabkan NullReferenceException dilemparkan. Idiom yang digunakan untuk mengatasi masalah ini lebih rumit daripada pemeriksaan null sederhana, dan dibahas nanti dalam seri ini.

Menetapkan, menambahkan, dan menghapus target pemanggilan

Begitulah cara jenis delegasi didefinisikan, dan bagaimana instans delegasi dideklarasikan dan dipanggil.

Pengembang yang ingin menggunakan List.Sort() metode perlu menentukan metode yang tanda tangannya cocok dengan definisi jenis delegasi, dan menetapkannya ke delegasi yang digunakan oleh metode pengurutan. Tugas ini menambahkan metode ke daftar pemanggilan objek delegasi tersebut.

Misalkan Anda ingin mengurutkan daftar string berdasarkan panjangnya. Fungsi perbandingan Anda mungkin sebagai berikut:

private static int CompareLength(string left, string right) =>
    left.Length.CompareTo(right.Length);

Metode ini dinyatakan sebagai metode pribadi. Tidak apa-apa. Anda mungkin tidak ingin metode ini menjadi bagian dari antarmuka publik Anda. Ini masih dapat digunakan sebagai metode perbandingan ketika melekat pada delegasi. Kode panggilan akan memiliki metode ini dilampirkan ke daftar target objek delegasi, dan dapat mengaksesnya melalui delegasi itu.

Anda membuat hubungan tersebut dengan meneruskan metode tersebut ke List.Sort() metode :

phrases.Sort(CompareLength);

Perhatikan bahwa nama metode digunakan, tanpa tanda kurung. Menggunakan metode sebagai argumen memberitahu compiler untuk mengkonversi referensi metode menjadi referensi yang dapat digunakan sebagai target pemanggilan delegasi, dan melampirkan metode itu sebagai target pemanggilan.

Anda juga bisa eksplisit dengan mendeklarasikan variabel jenis Comparison<string> dan melakukan penugasan:

Comparison<string> comparer = CompareLength;
phrases.Sort(comparer);

Dalam penggunaan di mana metode yang digunakan sebagai target delegasi adalah metode kecil, biasanya menggunakan sintaks ekspresi lambda untuk melakukan penugasan:

Comparison<string> comparer = (left, right) => left.Length.CompareTo(right.Length);
phrases.Sort(comparer);

Menggunakan ekspresi lambda untuk mendelegasikan target dibahas lebih lanjut di bagian selanjutnya.

Contoh Sort() biasanya melampirkan satu metode target ke delegasi. Namun, objek delegasi mendukung daftar pemanggilan yang memiliki beberapa metode target yang dilampirkan ke objek delegasi.

Kelas Delegasi dan MulticastDelegate

Dukungan bahasa yang dijelaskan di atas menyediakan fitur dan dukungan yang biasanya Anda perlukan untuk bekerja dengan delegasi. Fitur-fitur ini dibangun di atas dua kelas dalam kerangka kerja .NET Core: Delegate dan MulticastDelegate.

Kelas System.Delegate dan subkelas langsung tunggalnya, System.MulticastDelegate, memberikan dukungan kerangka kerja untuk membuat delegasi, mendaftarkan metode sebagai target delegasi, dan memanggil semua metode yang terdaftar sebagai target delegasi.

Menariknya, System.Delegate kelas dan System.MulticastDelegate tidak sendiri mendelegasikan jenis. Mereka memberikan dasar untuk semua jenis delegasi tertentu. Proses desain bahasa yang sama mengamanatkan bahwa Anda tidak dapat mendeklarasikan kelas yang berasal dari Delegate atau MulticastDelegate. Aturan bahasa C # melarangnya.

Sebaliknya, pengkompilasi C# membuat instans kelas yang berasal dari MulticastDelegate saat Anda menggunakan kata kunci bahasa C# untuk mendeklarasikan jenis delegasi.

Desain ini berakar pada rilis pertama C # dan .NET. Salah satu tujuan untuk tim desain adalah untuk memastikan bahwa bahasa ditegakkan jenis keselamatan saat menggunakan delegasi. Itu berarti memastikan bahwa delegasi dipanggil dengan jenis dan jumlah argumen yang tepat. Dan, bahwa setiap jenis pengembalian ditunjukkan dengan benar pada waktu kompilasi. Delegasi adalah bagian dari rilis 1.0 .NET, yang sebelum generik.

Cara terbaik untuk menegakkan keselamatan jenis ini adalah agar kompiler membuat kelas delegasi konkret yang mewakili tanda tangan metode yang digunakan.

Meskipun Anda tidak dapat membuat kelas turunan secara langsung, Anda akan menggunakan metode yang ditentukan pada kelas-kelas ini. Mari kita pergi melalui metode yang paling umum yang akan Anda gunakan ketika Anda bekerja dengan delegasi.

Fakta pertama yang paling penting untuk diingat adalah bahwa setiap delegasi yang bekerja sama dengan Anda berasal dari MulticastDelegate. Delegasi multicast berarti bahwa lebih dari satu target metode dapat dipanggil saat mengajukan melalui delegasi. Desain asli dianggap membuat perbedaan antara delegasi di mana hanya satu metode target dapat dilampirkan dan dipanggil, dan delegasi di mana beberapa metode target dapat dilampirkan dan dipanggil. Perbedaan itu terbukti kurang berguna dalam praktik daripada yang diperkirakan sebelumnya. Dua kelas yang berbeda sudah dibuat, dan telah berada dalam kerangka kerja sejak rilis publik awalnya.

Metode yang paling banyak Anda gunakan dengan delegasi adalah Invoke() dan BeginInvoke() / EndInvoke(). Invoke() akan memanggil semua metode yang telah dilampirkan ke instans delegasi tertentu. Seperti yang Anda lihat di atas, Anda biasanya memanggil delegasi menggunakan sintaks panggilan metode pada variabel delegasi. Seperti yang akan Anda lihat nanti dalam seri ini, ada pola yang berfungsi langsung dengan metode ini.

Sekarang setelah Anda melihat sintaks bahasa dan kelas yang mendukung delegasi, mari kita periksa seberapa kuat delegasi yang diketik digunakan, dibuat, dan dipanggil.

Berikutnya