Apa itu penutupan ? Apakah kita memilikinya di .NET?
Jika ada di .NET, bisakah Anda memberikan cuplikan kode (lebih disukai dalam C #) yang menjelaskannya?
Saya punya artikel tentang topik ini . (Ada banyak contoh.)
Pada dasarnya, penutupan adalah blok kode yang dapat dieksekusi di lain waktu, tetapi yang mempertahankan lingkungan di mana ia pertama kali dibuat - yaitu masih dapat menggunakan variabel lokal dll dari metode yang membuatnya, bahkan setelah itu Metode telah selesai dieksekusi.
Fitur umum penutupan diimplementasikan dalam C # dengan metode anonim dan ekspresi lambda.
Berikut ini contoh menggunakan metode anonim:
using System;
class Test
{
static void Main()
{
Action action = CreateAction();
action();
action();
}
static Action CreateAction()
{
int counter = 0;
return delegate
{
// Yes, it could be done in one statement;
// but it is clearer like this.
counter++;
Console.WriteLine("counter={0}", counter);
};
}
}
Keluaran:
counter=1
counter=2
Di sini kita dapat melihat bahwa tindakan yang dikembalikan oleh CreateAction masih memiliki akses ke variabel penghitung, dan memang dapat meningkatkannya, meskipun CreateAction sendiri telah selesai.
counter
tersedia untuk ditambahkan - kompilator menghasilkan kelas yang berisicounter
bidang, dan kode apa pun yang merujuk padacounter
akhirnya melalui turunan dari kelas itu.Jika Anda tertarik melihat bagaimana C # mengimplementasikan Penutupan, baca "Saya tahu jawabannya (42) blognya"
Compiler menghasilkan kelas di latar belakang untuk merangkum metode anoymous dan variabel j
untuk fungsi:
Mengubahnya menjadi:
sumber
Penutupan adalah nilai fungsional yang menahan nilai variabel dari ruang lingkup aslinya. C # dapat menggunakannya dalam bentuk delegasi anonim.
Untuk contoh yang sangat sederhana, ambil kode C # ini:
Pada akhirnya, bar akan diatur ke 4, dan delegasi myClosure dapat diedarkan untuk digunakan di tempat lain dalam program ini.
Penutup dapat digunakan untuk banyak hal berguna, seperti eksekusi yang tertunda atau untuk menyederhanakan antarmuka - LINQ terutama dibangun menggunakan penutupan. Cara yang paling langsung berguna bagi sebagian besar pengembang adalah menambahkan pengendali acara ke kontrol yang dibuat secara dinamis - Anda dapat menggunakan penutupan untuk menambah perilaku saat kontrol digunakan, daripada menyimpan data di tempat lain.
sumber
Penutupan adalah fungsi anonim yang dilewatkan di luar fungsi yang dibuatnya. Itu memelihara setiap variabel dari fungsi di mana ia dibuat yang digunakannya.
sumber
Berikut adalah contoh buat untuk C # yang saya buat dari kode serupa di JavaScript:
Jadi, berikut adalah beberapa kode yang menunjukkan cara menggunakan kode di atas ...
Harapan itu agak membantu.
sumber
Penutupan pada dasarnya adalah blok kode yang bisa Anda berikan sebagai argumen ke suatu fungsi. C # mendukung penutupan dalam bentuk delegasi anonim.
Berikut ini adalah contoh sederhana:
Metode List.Find dapat menerima dan mengeksekusi sepotong kode (penutupan) untuk menemukan item daftar.
Dengan menggunakan sintaks C # 3.0 kita dapat menulis ini sebagai:
sumber
Penutupan adalah ketika suatu fungsi didefinisikan di dalam fungsi lain (atau metode) dan itu menggunakan variabel dari metode induk . Ini penggunaan variabel yang terletak di suatu metode dan dibungkus dengan fungsi yang didefinisikan di dalamnya, disebut penutupan.
Mark Seemann memiliki beberapa contoh penutupan yang menarik di posting blognya di mana ia melakukan paralel antara pemrograman oop dan fungsional.
Dan untuk membuatnya lebih detail
sumber
Penutupan adalah potongan kode yang mereferensikan variabel di luar dirinya, (dari bawahnya di stack), yang dapat dipanggil atau dieksekusi nanti, (seperti ketika suatu peristiwa atau delegasi didefinisikan, dan dapat dipanggil pada waktu tertentu di masa mendatang. ) ... Karena variabel luar yang potongan referensi kode mungkin keluar dari ruang lingkup (dan jika tidak akan hilang), fakta bahwa itu direferensikan oleh potongan kode (disebut penutupan) memberitahu runtime untuk "menahan "variabel tersebut dalam ruang lingkup sampai tidak lagi diperlukan oleh penutupan kode ...
sumber
Saya telah mencoba memahaminya juga, jauh di bawah ini adalah potongan kode untuk Kode yang sama dalam Javascript dan C # menunjukkan penutupan.
JavaScript:
C #:
JavaScript:
C #:
sumber
Tiba-tiba, jawaban yang sederhana dan lebih pengertian dari buku C # 7.0 singkatnya.
Pra-syarat Anda harus tahu : Ekspresi lambda dapat merujuk variabel lokal dan parameter metode yang didefinisikan (variabel luar).
Bagian nyata : Variabel luar yang dirujuk oleh ekspresi lambda disebut variabel yang ditangkap. Ekspresi lambda yang menangkap variabel disebut closure.
Poin terakhir yang perlu diperhatikan : Variabel yang diambil dievaluasi ketika delegasi benar-benar dipanggil, bukan ketika variabel ditangkap:
sumber
Jika Anda menulis metode anonim sebaris (C # 2) atau (lebih disukai) ekspresi Lambda (C # 3 +), metode aktual masih dibuat. Jika kode itu menggunakan variabel lokal luar-lingkup - Anda masih harus meneruskan variabel itu ke metode.
misalnya ambil klausa Linq Where ini (yang merupakan metode ekstensi sederhana yang melewati ekspresi lambda):
jika Anda ingin menggunakan i dalam ekspresi lambda, Anda harus meneruskannya ke metode yang dibuat.
Jadi pertanyaan pertama yang muncul adalah: haruskah itu diteruskan dengan nilai atau referensi?
Lulus dengan referensi (saya kira) lebih disukai ketika Anda mendapatkan akses baca / tulis ke variabel itu (dan inilah yang dilakukan C #; Saya kira tim di Microsoft menimbang pro dan kontra dan melanjutkan dengan referensi; Menurut Jon Skeet's artikel , Java berjalan dengan nilai).
Tetapi kemudian muncul pertanyaan lain: Di mana saya harus mengalokasikan itu?
Haruskah itu benar-benar / secara alami dialokasikan pada tumpukan? Nah, jika Anda mengalokasikannya di stack dan meneruskannya dengan referensi, mungkin ada situasi di mana ia hidup lebih lama dari frame stack itu sendiri. Ambil contoh ini:
Ekspresi lambda (dalam klausa Dimana) sekali lagi menciptakan metode yang mengacu pada i. Jika saya dialokasikan pada tumpukan Outlive, maka pada saat Anda menyebutkan whereItems, saya yang digunakan dalam metode yang dihasilkan akan menunjuk ke saya dari Outlive, yaitu ke tempat di tumpukan yang tidak lagi dapat diakses.
Ok, jadi kita membutuhkannya di heap.
Jadi apa yang dilakukan oleh kompiler C # untuk mendukung inline anonim / lambda ini, adalah menggunakan apa yang disebut " Penutup ": Ini menciptakan kelas pada Heap yang disebut ( agak buruk ) DisplayClass yang memiliki bidang yang berisi i, dan Fungsi yang benar-benar menggunakan Itu.
Sesuatu yang setara dengan ini (Anda dapat melihat IL yang dihasilkan menggunakan ILSpy atau ILDASM):
Instantiate kelas itu dalam lingkup lokal Anda, dan menggantikan kode apa pun yang berkaitan dengan saya atau ekspresi lambda dengan instance penutupan itu. Jadi - kapan pun Anda menggunakan i dalam kode "ruang lingkup lokal" tempat saya didefinisikan, Anda sebenarnya menggunakan bidang instance DisplayClass.
Jadi jika saya akan mengubah "lokal" i dalam metode utama, itu sebenarnya akan mengubah _DisplayClass.i;
yaitu
itu akan mencetak 12, karena "i = 10" pergi ke bidang dispalyclass dan mengubahnya tepat sebelum enumerasi ke-2.
Sumber yang baik tentang topik ini adalah modul Bart De Smet Pluralsight ini (memerlukan pendaftaran) (juga mengabaikan penggunaan istilah "Hoisting" yang salah - maksudnya adalah variabel lokal (yaitu i) diubah untuk merujuk ke bidang DisplayClass baru).
Dalam berita lain, tampaknya ada beberapa kesalahpahaman bahwa "Penutupan" terkait dengan loop - seperti yang saya mengerti "Penutupan" BUKAN sebuah konsep yang terkait dengan loop , tetapi lebih kepada metode anonim / ekspresi lambda penggunaan variabel cakupan lokal - meskipun beberapa trik pertanyaan menggunakan loop untuk menunjukkannya.
sumber
Penutupan adalah fungsi, yang didefinisikan dalam suatu fungsi, yang dapat mengakses variabel lokal dan juga induknya.
jadi fungsi di dalam metode find.
dapat mengakses variabel di dalam ruang lingkupnya, t, dan nama variabel yang ada dalam ruang lingkup orang tuanya. Meskipun dieksekusi oleh metode find sebagai delegasi, dari lingkup lain semuanya.
sumber