+1 untuk kombinasi langka menjadi baru dalam pengkodean dan mengajukan pertanyaan yang bagus: Anda memahami apa yang ingin Anda lakukan dan menjelaskannya dengan baik, Anda hanya tidak tahu istilahnya sehingga Anda tidak dapat menemukannya sendiri.
Untuk kelengkapan (sehubungan dengan berbagai komentar) ...
Seperti yang dikatakan Erik, Anda dapat mengeksekusi beberapa baris kode:
varButtonClicked=newAction(()=>{MessageBox.Show("hi");MessageBox.Show("something else");// something more useful than another popup ;)});
Seperti yang dikatakan Tim, Anda dapat menghilangkan Actionkata kunci tersebut
ActionButtonClicked=()=>MessageBox.Show("hi");ActionButtonClicked=()=>{// multiple lines of code};
Untuk mengatasi komentar KRyan, mengenai tanda kurung kosong, yang mewakili daftar parameter yang ingin Anda kirimkan ke Action (dalam hal ini, tidak ada) .
Jika, misalnya, Anda ingin menentukan pesan ke acara, Anda bisa menambahkan "pesan" sebagai parameter (catatan bahwa saya berubah Actionuntuk untuk menentukan parameter string tunggal) :Action<string>
Action ButtonClicked = () => MessageBox.Show("hi");setara dan IMO lebih baik (tambahkan parens jika Anda suka)
Tim S.
1
Tindakan juga dapat diselesaikan ke lebih dari satu baris kode.
Erik Philips
2
@CSharpie Saya tidak yakin bahwa membuat asumsi itu berguna untuk OP.
Erik Philips
2
@CSharpie Mengapa OP tidak menggunakan ini WinForms?
vivat pisces
2
@CSharpie Saya melihat apa yang Anda katakan. Jika dia benar-benar melampirkan ini ke Button.Clickacara, dan tidak menyimpannya dalam variabel yang kebetulan dia beri nama ButtonClicked.
vivat pisces
51
Dalam kasus Anda, Anda ingin menggunakan file delegate.
Mari kita lihat bagaimana seorang delegasi bekerja dan bagaimana kita bisa mendapatkan formulir yang lebih mudah dengan memahami konsepnya:
// Create a normal functionvoidOnButtonClick(){MessageBox.Show("Hello World!");}// Now we create a delegate called ButtonClickdelegatevoidButtonClick();
Anda lihat, delegasi mengambil bentuk fungsi normal tetapi tanpa argumen apa pun (Ini bisa menggunakan sejumlah argumen seperti metode lain, tetapi demi kesederhanaan, tidak).
Sekarang, mari gunakan apa yang kita miliki; kita akan mendefinisikan delegasi seperti kita mendefinisikan variabel lainnya:
Kami pada dasarnya membuat variabel baru bernama ButtonClicked, yang memiliki jenis ButtonClick (yang merupakan delegasi) dan ketika digunakan, akan mengeksekusi metode dalam metode OnButtonClick ().
Untuk menggunakannya kita cukup memanggil:ButtonClicked();
Jadi keseluruhan kodenya adalah:
delegatevoidButtonClick();voidOnButtonClick(){MessageBox.Show("Hello World!");}voidFoo(){ButtonClickButtonClicked=newButtonClick(OnButtonClick);ButtonClicked();// Execute the function.}
Dari sini, kita dapat beralih ke ekspresi lambda dan melihat bagaimana mereka dapat berguna dalam situasi Anda:
Ada banyak delegasi yang sudah ditentukan oleh pustaka .NET, dengan beberapa seperti Action, yang tidak menerima parameter apa pun dan tidak mengembalikan nilai. Ini didefinisikan sebagai public delegate void Action();
Anda selalu dapat menggunakannya untuk kebutuhan Anda alih-alih kebutuhan untuk menentukan delegasi baru setiap saat. Dalam konteks sebelumnya misalnya, Anda bisa saja baru saja menulis
yang akan melakukan hal yang sama.
Sekarang Anda telah melihat berbagai cara menggunakan delegasi, mari gunakan ekspresi lambda pertama kita. Ekspresi lambda adalah fungsi anonim; jadi, itu adalah fungsi normal tetapi tanpa nama. Mereka adalah dari bentuk-bentuk itu:
x =>DoSomethingWithX(x);(x)=>DoSomethingWithX(x);(x,y)=>DoSometingWithXY(x,y);()=>Console.WriteLine("I do not have parameters!");
Dalam kasus kami, kami tidak memiliki parameter apa pun jadi kami akan menggunakan ekspresi terakhir. Kita bisa menggunakan ini hanya sebagai fungsi OnButtonClick, tapi kita mendapat keuntungan karena tidak memiliki fungsi bernama. Sebagai gantinya kita bisa melakukan sesuatu seperti ini:
maka cukup panggil ButtonClicked();Tentu saja Anda juga dapat memiliki beberapa baris kode, tetapi saya tidak ingin membingungkan Anda lagi. Akan terlihat seperti ini:
Anda juga bisa bermain-main, misalnya, Anda dapat menjalankan fungsi seperti ini:
newAction(()=>MessageBox.Show("Hello World!"))();
Maaf untuk postingan yang panjang, semoga tidak terlalu membingungkan :)
EDIT: Saya lupa menyebutkan bahwa bentuk alternatif yang, meskipun tidak sering digunakan, dapat membuat ekspresi lambda lebih mudah dipahami:
newAction(delegate(){Console.WriteLine("I am parameterless");})();
Juga, menggunakan obat generik:
// Defines a delegate that has one parameter of type string. You could pass as many parameters as you want.newAction<string>(delegate(string x){Console.WriteLine(x);})("I am a string parameter!");
Pada gilirannya, Anda dapat menggunakan ekspresi lambda, tetapi Anda tidak perlu (tetapi mungkin dalam beberapa kasus) untuk menentukan jenis parameter, misalnya, kode di atas dapat dengan mudah ditulis sebagai:
newAction<string>(x =>{Console.WriteLine(x);})("I am a string parameter!");
atau:
newAction<string>(x =>Console.WriteLine(x))("I am a string parameter!");
EDIT2: Action<string>adalah representasi dari public void delegate Action(string obj); Action<string,string>adalah representasi public void delegate Action(string obj, string obj2);
Secara umum, Action<T>adalah representasi daripublic void delegate Action<T>(T obj);
EDIT3: Saya tahu posnya sudah ada di sini untuk sementara waktu, tetapi saya pikir ini sangat keren untuk tidak disebutkan: Anda dapat melakukan ini, yang sebagian besar terkait dengan pertanyaan Anda:
The Lazykelas khusus dirancang untuk mewakili nilai yang tidak akan dihitung sampai Anda meminta untuk itu. Anda membangunnya dengan menyediakan metode yang menentukan bagaimana itu harus dibangun, tetapi itu akan menangani eksekusi metode itu tidak lebih dari sekali (bahkan saat menghadapi beberapa utas yang meminta nilai) dan hanya mengembalikan nilai yang sudah dibangun untuk permintaan tambahan apa pun:
var foo =newLazy<DialogResult>(()=>MessageBox.Show("Hello, World!"));var result = foo.Value;
Ingat itu Lazyharus digunakan untuk nilai yang membutuhkan banyak daya pemrosesan, dan Anda tidak boleh menggunakannya untuk interaksi (karena semantiknya .Valueadalah ia mengembalikan nilai, mirip dengan properti, bukan tindakan (interaktif)). Sebagai gantinya, seorang delegasi harus digunakan untuk tindakan semacam itu.
Abel
1
@Abel Tidak, ini bukan untuk nilai yang membutuhkan banyak daya pemrosesan, ini untuk nilai apa pun yang ingin Anda tunda inisialisasi hingga diminta, sementara tidak pernah menginisialisasi nilai itu lebih dari sekali. Sini nilai Valueyang digunakan; itu DialogResultditerima dari menampilkan kotak pesan. Perbedaan utama antara solusi ini dan penggunaan delegasi adalah apakah nilai harus dihitung ulang setiap kali diminta atau tidak. Interpretasi saya tentang persyaratan adalah bahwa ini secara konseptual menginisialisasi nilai, bukan operasi yang akan diulang.
Pelayanan
Lazydapat dengan mudah digunakan secara salah. Ini memiliki overhead sendiri, menggunakannya "hanya" untuk menunda tugas kecil akan meminta lebih banyak overhead daripada keuntungannya. Menampilkan kotak pesan dari suatu properti adalah (imo) praktik buruk secara umum, terlepas dari Lazy. Btw, dari MSDN, saya mengutip: "Gunakan inisialisasi malas untuk menunda pembuatan objek yang besar atau intensif sumber daya" . Anda bisa saja tidak setuju dengan itu, tapi itu memang awalnya dirancang untuk itu.
Abel
1
@Abel Overhead kinerja untuk Lazykonteks seperti ini tentunya dapat diabaikan; itu akan sepi dibandingkan dengan waktu yang dihabiskan menunggu manusia untuk mengklik kotak pesan. Ini sebagian besar bermuara pada persyaratan nyata dari aplikasi yang mendasarinya; ketidakjelasan pertanyaan membuat jawaban yang benar secara objektif menjadi tidak mungkin. Ini adalah salah satu interpretasi dari pertanyaan tersebut. Adapun melakukan banyak pekerjaan di properti getter menjadi buruk; tampaknya Anda pada dasarnya menentang keseluruhan desain Lazy. Terima kasih atas opini itu.
Pelayanan
Maaf, Anda pasti salah paham dengan saya. Tentu saja, dengan MessageBox overhead dapat diabaikan (saya tidak akan menggunakan UI di dalam properti). Maksud saya tugas-tugas kecil secara umum (seperti menunda 2 + 3 * 4 / i), di mana biaya pembuatan penutupan lebih besar daripada perhitungan itu sendiri. Dan saya pikir saya sepenuhnya merangkul Lazy, pada kenyataannya kami banyak menggunakannya di F # (sedikit lebih sedikit di C #) dan kami telah belajar dengan cara yang sulit bahwa Anda harus berhati-hati dengannya, khususnya. sehubungan dengan kinerja.
Abel
4
Cara saya membaca pertanyaan Anda, apakah ini dalam konteks kontrol GUI?
Anda dapat menetapkan kode C # ke variabel, mengkompilasinya saat runtime dan menjalankan kode:
Tulis kode Anda:
// Assign C# code to the code variable.string code =@"
using System;
namespace First
{
public class Program
{
public static void Main()
{
"+"Console.WriteLine(\"Hello, world!\");"+@"
}
}
}
";
Jawaban:
Anda dapat menetapkannya
Action
seperti ini:Kemudian sebut saja:
Untuk kelengkapan (sehubungan dengan berbagai komentar) ...
Seperti yang dikatakan Erik, Anda dapat mengeksekusi beberapa baris kode:
Seperti yang dikatakan Tim, Anda dapat menghilangkan
Action
kata kunci tersebutUntuk mengatasi komentar KRyan, mengenai tanda kurung kosong, yang mewakili daftar parameter yang ingin Anda kirimkan ke Action (dalam hal ini, tidak ada) .
Jika, misalnya, Anda ingin menentukan pesan ke acara, Anda bisa menambahkan "pesan" sebagai parameter (catatan bahwa saya berubah
Action
untuk untuk menentukan parameter string tunggal) :Action<string>
sumber
Action ButtonClicked = () => MessageBox.Show("hi");
setara dan IMO lebih baik (tambahkan parens jika Anda suka)WinForms
?Button.Click
acara, dan tidak menyimpannya dalam variabel yang kebetulan dia beri namaButtonClicked
.Dalam kasus Anda, Anda ingin menggunakan file
delegate
.Mari kita lihat bagaimana seorang delegasi bekerja dan bagaimana kita bisa mendapatkan formulir yang lebih mudah dengan memahami konsepnya:
Anda lihat, delegasi mengambil bentuk fungsi normal tetapi tanpa argumen apa pun (Ini bisa menggunakan sejumlah argumen seperti metode lain, tetapi demi kesederhanaan, tidak).
Sekarang, mari gunakan apa yang kita miliki; kita akan mendefinisikan delegasi seperti kita mendefinisikan variabel lainnya:
Kami pada dasarnya membuat variabel baru bernama ButtonClicked, yang memiliki jenis ButtonClick (yang merupakan delegasi) dan ketika digunakan, akan mengeksekusi metode dalam metode OnButtonClick ().
Untuk menggunakannya kita cukup memanggil:
ButtonClicked();
Jadi keseluruhan kodenya adalah:
Dari sini, kita dapat beralih ke ekspresi lambda dan melihat bagaimana mereka dapat berguna dalam situasi Anda:
Ada banyak delegasi yang sudah ditentukan oleh pustaka .NET, dengan beberapa seperti Action, yang tidak menerima parameter apa pun dan tidak mengembalikan nilai. Ini didefinisikan sebagai
public delegate void Action();
Anda selalu dapat menggunakannya untuk kebutuhan Anda alih-alih kebutuhan untuk menentukan delegasi baru setiap saat. Dalam konteks sebelumnya misalnya, Anda bisa saja baru saja menulis
yang akan melakukan hal yang sama.
Sekarang Anda telah melihat berbagai cara menggunakan delegasi, mari gunakan ekspresi lambda pertama kita. Ekspresi lambda adalah fungsi anonim; jadi, itu adalah fungsi normal tetapi tanpa nama. Mereka adalah dari bentuk-bentuk itu:
Dalam kasus kami, kami tidak memiliki parameter apa pun jadi kami akan menggunakan ekspresi terakhir. Kita bisa menggunakan ini hanya sebagai fungsi OnButtonClick, tapi kita mendapat keuntungan karena tidak memiliki fungsi bernama. Sebagai gantinya kita bisa melakukan sesuatu seperti ini:
atau bahkan lebih mudah,
maka cukup panggil
ButtonClicked();
Tentu saja Anda juga dapat memiliki beberapa baris kode, tetapi saya tidak ingin membingungkan Anda lagi. Akan terlihat seperti ini:Anda juga bisa bermain-main, misalnya, Anda dapat menjalankan fungsi seperti ini:
Maaf untuk postingan yang panjang, semoga tidak terlalu membingungkan :)
EDIT: Saya lupa menyebutkan bahwa bentuk alternatif yang, meskipun tidak sering digunakan, dapat membuat ekspresi lambda lebih mudah dipahami:
Juga, menggunakan obat generik:
Pada gilirannya, Anda dapat menggunakan ekspresi lambda, tetapi Anda tidak perlu (tetapi mungkin dalam beberapa kasus) untuk menentukan jenis parameter, misalnya, kode di atas dapat dengan mudah ditulis sebagai:
atau:
EDIT2:
Action<string>
adalah representasi daripublic void delegate Action(string obj);
Action<string,string>
adalah representasipublic void delegate Action(string obj, string obj2);
Secara umum,
Action<T>
adalah representasi daripublic void delegate Action<T>(T obj);
EDIT3: Saya tahu posnya sudah ada di sini untuk sementara waktu, tetapi saya pikir ini sangat keren untuk tidak disebutkan: Anda dapat melakukan ini, yang sebagian besar terkait dengan pertanyaan Anda:
atau sederhana:
sumber
The
Lazy
kelas khusus dirancang untuk mewakili nilai yang tidak akan dihitung sampai Anda meminta untuk itu. Anda membangunnya dengan menyediakan metode yang menentukan bagaimana itu harus dibangun, tetapi itu akan menangani eksekusi metode itu tidak lebih dari sekali (bahkan saat menghadapi beberapa utas yang meminta nilai) dan hanya mengembalikan nilai yang sudah dibangun untuk permintaan tambahan apa pun:sumber
Lazy
harus digunakan untuk nilai yang membutuhkan banyak daya pemrosesan, dan Anda tidak boleh menggunakannya untuk interaksi (karena semantiknya.Value
adalah ia mengembalikan nilai, mirip dengan properti, bukan tindakan (interaktif)). Sebagai gantinya, seorang delegasi harus digunakan untuk tindakan semacam itu.Value
yang digunakan; ituDialogResult
diterima dari menampilkan kotak pesan. Perbedaan utama antara solusi ini dan penggunaan delegasi adalah apakah nilai harus dihitung ulang setiap kali diminta atau tidak. Interpretasi saya tentang persyaratan adalah bahwa ini secara konseptual menginisialisasi nilai, bukan operasi yang akan diulang.Lazy
dapat dengan mudah digunakan secara salah. Ini memiliki overhead sendiri, menggunakannya "hanya" untuk menunda tugas kecil akan meminta lebih banyak overhead daripada keuntungannya. Menampilkan kotak pesan dari suatu properti adalah (imo) praktik buruk secara umum, terlepas dariLazy
. Btw, dari MSDN, saya mengutip: "Gunakan inisialisasi malas untuk menunda pembuatan objek yang besar atau intensif sumber daya" . Anda bisa saja tidak setuju dengan itu, tapi itu memang awalnya dirancang untuk itu.Lazy
konteks seperti ini tentunya dapat diabaikan; itu akan sepi dibandingkan dengan waktu yang dihabiskan menunggu manusia untuk mengklik kotak pesan. Ini sebagian besar bermuara pada persyaratan nyata dari aplikasi yang mendasarinya; ketidakjelasan pertanyaan membuat jawaban yang benar secara objektif menjadi tidak mungkin. Ini adalah salah satu interpretasi dari pertanyaan tersebut. Adapun melakukan banyak pekerjaan di properti getter menjadi buruk; tampaknya Anda pada dasarnya menentang keseluruhan desainLazy
. Terima kasih atas opini itu.MessageBox
overhead dapat diabaikan (saya tidak akan menggunakan UI di dalam properti). Maksud saya tugas-tugas kecil secara umum (seperti menunda2 + 3 * 4 / i
), di mana biaya pembuatan penutupan lebih besar daripada perhitungan itu sendiri. Dan saya pikir saya sepenuhnya merangkulLazy
, pada kenyataannya kami banyak menggunakannya di F # (sedikit lebih sedikit di C #) dan kami telah belajar dengan cara yang sulit bahwa Anda harus berhati-hati dengannya, khususnya. sehubungan dengan kinerja.Cara saya membaca pertanyaan Anda, apakah ini dalam konteks kontrol GUI?
Jika ini ada di WPF, lihat cara yang "benar" untuk menangani perintah dari kontrol: http://msdn.microsoft.com/en-us/library/ms752308(v=vs.110).aspx
... tapi itu bisa menjadi sakit dan berlebihan. Untuk kasus umum yang lebih sederhana, Anda mungkin mencari pengendali event, seperti:
Penangan kejadian itu dapat ditangani dengan berbagai cara. Contoh di atas menggunakan fungsi anonim, tetapi Anda juga dapat melakukan:
... seperti yang Anda tanyakan, dengan fungsi (atau di sini, "Action", karena mengembalikan void) yang ditetapkan sebagai variabel.
sumber
Anda dapat menetapkan kode C # ke variabel, mengkompilasinya saat runtime dan menjalankan kode:
Tulis kode Anda:
Buat penyedia dan parameter kompilator:
Tentukan parameter kompilator:
Kompilasi perakitan:
Periksa kesalahan:
Dapatkan perakitan, jenis dan metode Utama:
Menjalankannya:
Referensi:
http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime
sumber