Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Tip
Baru mengembangkan perangkat lunak? Mulai dengan tutorial Memulai terlebih dahulu. Bangun keterampilan tipe dasar dan metode terlebih dahulu sebelum Anda menggunakan ekspresi lambda.
Terkadang Anda ingin meneruskan perilaku kecil, fungsi, langsung ke metode lain. Misalnya, Anda mungkin ingin memfilter daftar, tetapi kondisi pemfilteran berubah tergantung pada situasinya. Daripada menulis metode bernama terpisah untuk setiap kondisi yang mungkin, Anda meneruskan kondisi itu sendiri sebagai argumen.
Ekspresi Lambda adalah fitur C# yang memungkinkan hal ini. Ekspresi lambda adalah fungsi sebaris yang ringkas yang Anda tulis tanpa memberinya nama. Anda menggunakan operator => panah untuk memisahkan daftar parameter dari isi:
x => x * 2
Membaca kiri ke kanan: x adalah parameter input, => berarti "masuk ke," dan x * 2 merupakan isinya. Ini menghitung nilai yang akan dikembalikan. Ketika tidak ada parameter atau lebih dari satu, bungkus dalam tanda kurung: () => 42 atau (left, right) => left + right.
Delegasi mendukung ekspresi lambda
Untuk menggunakan ekspresi lambda, pengkompilasi C# perlu mengetahui dua hal: jenis parameter dan jenis pengembalian. Deskripsi itu, jenis parameter ditambah jenis pengembalian, disebut jenis delegasi.
Jenis delegasi adalah jenis yang mewakili signatur metode. Variabel jenis delegasi dapat menyimpan metode yang cocok seperti ekspresi lambda atau metode bernama, selama jenis parameter dan jenis pengembaliannya cocok.
Anda menyatakan jenis delegasi dengan delegate kata kunci:
delegate int Transform(int value);
Deklarasi ini mengatakan: "Transform adalah jenis delegasi untuk metode yang menerimanya int dan mengembalikan int." Anda kemudian dapat menetapkan ekspresi lambda atau metode bernama ke variabel jenis tersebut:
Transform doubler = x => x * 2; // assign a lambda expression
Transform squarer = Square; // assign a named method
Console.WriteLine(doubler(5)); // 10
Console.WriteLine(squarer(5)); // 25
static int Square(int value) => value * value;
Baik doubler maupun squarer memiliki nilai jenis Transform. Anda menyebutnya persis seperti metode biasa. Pengkompilasi memverifikasi bahwa apa pun yang Anda tetapkan cocok dengan tanda tangan yang dideklarasikan.
Jenis delegasi bawaan: Func dan Action
Mendeklarasikan jenis delegasi kustom untuk setiap situasi dapat berulang. .NET menyediakan dua keluarga jenis delegasi generik, Func dan Action, yang mencakup sebagian besar skenario, jadi Anda jarang perlu menggunakan kata kunci delegate sendiri.
Kedua keluarga tipe datang dalam versi dengan parameter jenis input nol hingga enam belas, sehingga mereka dapat mengakomodasi berbagai jumlah input. Perbedaan utama antara kedua keluarga adalah:
-
System.Func<T,TResult> (dan
Func<T1, T2, TResult>, dan sebagainya) mewakili metode yang mengembalikan nilai. Parameter jenis terakhir selalu merupakan jenis pengembalian; semua yang sebelumnya adalah jenis input. -
System.Action<T> (dan
Action<T1, T2>, dan sebagainya) mewakili metode yang tidak mengembalikan apa pun (void). Semua parameter tipe adalah tipe input. System.Action tanpa parameter jenis mewakili metode tanpa input dan tidak ada nilai yang dikembalikan.
Misalnya, Func<int, int, int> menjelaskan metode dengan dua int input dan satu int hasil.
Action<string> menjelaskan metode dengan satu string input dan tidak ada nilai yang dikembalikan.
Func<int, int, int> add = (left, right) => left + right;
Action<string> report = message => Console.WriteLine($"Report: {message}");
int total = add(5, 9);
report($"5 + 9 = {total}");
Gunakan nama parameter deskriptif dalam lambda sehingga pembaca dapat memahami niat tanpa memindai isi metode lengkap.
Meneruskan ekspresi lambda ke metode
Saat metode mendeklarasikan Func parameter atau Action , penelepon meneruskan ekspresi lambda yang cocok dengan jenis delegasi tersebut. Kompilator memeriksa bahwa jenis parameter lambda dan jenis pengembalian cocok dengan jenis delegasi yang dinyatakan. Jika tidak cocok, kode tidak dikompilasi.
int[] numbers = [1, 2, 3, 4, 5, 6];
int[] evenNumbers = Filter(numbers, value => value % 2 == 0).ToArray();
Console.WriteLine(string.Join(", ", evenNumbers));
Metode Filter mendeklarasikan parameter Func<int, bool> yang bernama predicate. Tipe ini memberi tahu pemanggil bentuk yang diharapkan: satu masukan, satu hasil. Pemanggil melewati value => value % 2 == 0 sebagai argumen tersebut. Pola ini muncul di seluruh LINQ dan banyak API .NET.
Pertahankan ekspresi lambda terpisah
Ekspresi lambda dapat mereferensikan variabel dari kode di sekitarnya. Menangkap berarti lambda memegang referensi ke variabel yang dideklarasikan di luar tubuhnya sendiri. Kombinasi lambda dan variabel yang ditangkapnya disebut penutupan.
Ketika Anda tidak perlu menangkap apa pun, tambahkan pengubah static ke dalam lambda. Lambda statis hanya dapat menggunakan parameter dan nilainya sendiri yang dideklarasikan di dalam tubuhnya. Ini tidak dapat menangkap variabel lokal atau status instans dari lingkup yang melingkupi.
Func<int, bool> isEven = static value => value % 2 == 0;
Console.WriteLine(isEven(14));
Console.WriteLine(isEven(15));
Lambda statis membuat niat menjadi jelas dan mencegah penangkapan yang tidak disengaja.
Gunakan parameter buang saat input tidak relevan
Terkadang tanda tangan delegasi menyertakan parameter yang tidak Anda butuhkan. Gunakan perintah buang _ untuk memberi sinyal pilihan tersebut secara eksplisit.
Contoh umum termasuk penanganan aktivitas di mana Anda tidak menggunakan sender atau EventArgs, panggilan balik di mana Anda hanya memerlukan beberapa input, dan kelebihan beban LINQ yang menyediakan indeks yang tidak Anda gunakan.
Action<int, int, string> statusUpdate = (_, _, message) => Console.WriteLine(message);
statusUpdate(200, 42, "Operation completed");
Mengabaikan parameter yang tidak penting meningkatkan pemahaman karena menunjukkan parameter mana yang penting.
Peristiwa menyediakan pemberitahuan opsional
Peristiwa adalah mekanisme yang digunakan satu objek (penerbit) untuk memberi tahu objek lain (pelanggan) ketika sesuatu terjadi. Penerbit tidak perlu tahu siapa yang mendengarkan atau berapa banyak pelanggan yang ada. Pelanggan memilih untuk ikut serta.
Event dibangun berdasarkan delegate. Peristiwa adalah bidang delegasi dengan batasan tambahan yang diberlakukan oleh event kata kunci: kode luar hanya dapat berlangganan (+=) atau berhenti berlangganan (-=) dari peristiwa; hanya kelas yang menyatakan peristiwa dapat memanggil (menaikkannya).
Konvensi .NET untuk tipe delegasi acara System.EventHandler<TEventArgs>, di mana T adalah tipe data yang disertakan dengan notifikasi. Tanda tangannya selalu memiliki dua parameter: sender (objek yang menaikkan peristiwa) dan data peristiwa jenis T.
MessagePublisher publisher = new();
publisher.MessagePublished += (_, message) => Console.WriteLine($"Received: {message}");
publisher.Publish("Records updated");
Meninjau kode
-
MessagePublishermenyatakanevent EventHandler<string>? MessagePublished. Kataeventkunci berarti penelepon hanya dapat berlangganan atau berhenti berlangganan—mereka tidak dapat memanggilnya secara langsung. -
publisher.MessagePublished += (_, message) => ...melakukan berlangganan menggunakan ekspresi lambda._Membuangsenderparameter karena handler ini tidak membutuhkannya. -
publisher.Publish("Records updated")memicu kejadian dan menjalankan setiap handler yang terdaftar.
Berlangganan bersifat opsional.
?.Invoke(...) dalam metode Publish berarti peristiwa hanya terjadi ketika setidaknya satu pelanggan terhubung. Penerbit memicu acara tanpa mengetahui atau peduli apakah ada yang mendengar.