Saya ingin melakukan yang setara dengan yang berikut ini di LINQ, tapi saya tidak tahu caranya:
IEnumerable<Item> items = GetItems();
items.ForEach(i => i.DoStuff());
Apa sintaks yang sebenarnya?
linq
foreach
ienumerable
tags2k
sumber
sumber
ForEach()
.ForEach
ekstensi .foreach (var i in items) i.Dostuff();
Jawaban:
Tidak ada ekstensi ForEach untuk
IEnumerable
; hanya untukList<T>
. Jadi kamu bisa melakukannyaAtau, tulis metode ekstensi ForEach Anda sendiri:
sumber
IENumerable<T>
dalam metode ekstensi. Seperti:public static IEnumerable<T> ForAll<T>(this IEnumerable<T> numeration, Action<T> action) { foreach (T item in enumeration) { action(item); } return enumeration; }
Fredrik telah memberikan perbaikan, tetapi mungkin layak mempertimbangkan mengapa ini tidak dalam kerangka untuk memulai. Saya percaya idenya adalah bahwa operator kueri LINQ harus bebas efek samping, cocok dengan cara yang cukup fungsional dalam memandang dunia. Jelas ForEach justru sebaliknya - sebuah konstruksi berbasis efek samping murni .
Itu bukan untuk mengatakan ini adalah hal yang buruk untuk dilakukan - hanya memikirkan alasan filosofis di balik keputusan.
sumber
Seq.iter
tidak mengembalikan apa pun, apalagi seq baru dengan elemen efek samping. Ini hanya tentang efek samping. Anda mungkin berpikirSeq.map
, karenaSeq.iter
sama denganForEach
metode ekstensi aktifIEnumerabe<_>
.Pembaruan 7/17/2012: Rupanya pada C # 5.0, perilaku yang
foreach
dijelaskan di bawah ini telah diubah dan " penggunaanforeach
variabel iterasi dalam ekspresi lambda bersarang tidak lagi menghasilkan hasil yang tidak terduga. " Jawaban ini tidak berlaku untuk C # ≥ 5.0 .@John Skeet dan semua orang yang lebih suka kata kunci foreach.
Masalah dengan "foreach" dalam C # sebelum 5.0 , adalah bahwa itu tidak konsisten dengan cara yang setara "untuk pemahaman" bekerja dalam bahasa lain, dan dengan bagaimana saya mengharapkannya bekerja (pendapat pribadi yang dinyatakan di sini hanya karena orang lain telah menyebutkan mereka pendapat tentang keterbacaan). Lihat semua pertanyaan tentang " Akses ke penutupan yang dimodifikasi " serta " Menutup variabel loop yang dianggap berbahaya ". Ini hanya "berbahaya" karena cara "foreach" diimplementasikan dalam C #.
Ambil contoh berikut menggunakan metode ekstensi yang setara secara fungsional dengan yang ada di jawaban @Fredrik Kalseth.
Permintaan maaf untuk contoh yang terlalu dibuat-buat. Saya hanya menggunakan Observable karena tidak sepenuhnya diambil untuk melakukan sesuatu seperti ini. Jelas ada cara yang lebih baik untuk membuat ini dapat diamati, saya hanya berusaha menunjukkan suatu hal. Biasanya kode yang berlangganan observable dijalankan secara tidak serempak dan berpotensi di utas lainnya. Jika menggunakan "foreach", ini bisa menghasilkan hasil yang sangat aneh dan berpotensi non-deterministik.
Tes berikut menggunakan metode ekstensi "ForEach" lolos:
Berikut ini gagal dengan kesalahan:
Diharapkan: setara dengan <0, 1, 2, 3, 4, 5, 6, 7, 8, 9> Tetapi adalah: <9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9>
sumber
Anda dapat menggunakan
FirstOrDefault()
ekstensi yang tersedia untukIEnumerable<T>
. Dengan kembalifalse
dari predikat, itu akan dijalankan untuk setiap elemen tetapi tidak akan peduli bahwa itu tidak benar-benar menemukan kecocokan. Ini akan menghindariToList()
overhead.sumber
foreach(Item i in GetItems()) { i.DoStuff();}
Anda mengambil lebih banyak karakter dan membuatnya sangat membingungkanitems.All(i => { i.DoStuff(); return true; }
Saya mengambil metode Fredrik dan memodifikasi tipe pengembalian.
Dengan cara ini, metode ini mendukung eksekusi yang ditangguhkan seperti metode LINQ lainnya.
EDIT: Jika ini tidak jelas, segala penggunaan metode ini harus diakhiri dengan ToList () atau cara lain untuk memaksa metode untuk bekerja pada enumerable lengkap. Jika tidak, tindakan tidak akan dilakukan!
Dan inilah tes untuk membantu melihatnya:
Jika Anda menghapus ToList () pada akhirnya, Anda akan melihat tes gagal karena StringBuilder berisi string kosong. Ini karena tidak ada metode yang memaksa ForEach untuk menghitung.
sumber
ForEach
menarik, namun tidak sesuai dengan perilakuList.ForEach
, yang merupakan tanda tangannyapublic void ForEach(Action<T> action)
. Itu juga tidak cocok dengan perilakuObservable.ForEach
ekstensi untukIObservable<T>
, tanda tangan yangpublic static void ForEach<TSource>(this IObservable<TSource> source, Action<TSource> onNext)
. FWIW,ForEach
setara pada koleksi Scala, bahkan yang malas, juga memiliki tipe pengembalian yang setara dengan batal dalam C #.Select
denganToList
. TujuannyaForEach
adalah untuk tidak harus meneleponToList
. Itu harus dijalankan segera.Jauhkan Efek Samping Anda dari IEnumerable saya
Seperti yang orang lain tunjukkan di sini dan di luar negeri, LINQ dan
IEnumerable
metode diharapkan bebas efek samping.Apakah Anda benar-benar ingin "melakukan sesuatu" untuk setiap item di IEnumerable? Maka
foreach
merupakan pilihan terbaik. Orang-orang tidak terkejut ketika efek samping terjadi di sini.Saya yakin Anda tidak ingin efek samping
Namun dalam pengalaman saya efek samping biasanya tidak diperlukan. Lebih sering daripada tidak ada permintaan LINQ sederhana menunggu untuk ditemukan disertai dengan jawaban StackOverflow.com oleh Jon Skeet, Eric Lippert, atau Marc Gravell menjelaskan bagaimana melakukan apa yang Anda inginkan!
Beberapa contoh
Jika Anda sebenarnya hanya mengagregasi (mengakumulasi) beberapa nilai maka Anda harus mempertimbangkan
Aggregate
metode ekstensi.Mungkin Anda ingin membuat yang baru
IEnumerable
dari nilai yang ada.Atau mungkin Anda ingin membuat tabel pencarian:
Daftar (pun kata yang tidak sepenuhnya dimaksudkan) tentang kemungkinan berlanjut dan terus.
sumber
Jika Anda ingin bertindak sebagai gulungan enumerasi, Anda harus menghasilkan setiap item.
sumber
Ada rilis eksperimental oleh Microsoft untuk Interactive Extensions to LINQ (juga di NuGet , lihat profil RxTeams untuk tautan lainnya). Video Channel 9 menjelaskannya dengan baik.
Dokumennya hanya disediakan dalam format XML. Saya telah menjalankan dokumentasi ini di Sandcastle untuk membuatnya dalam format yang lebih mudah dibaca. Buka zip arsip docs dan cari index.html .
Di antara banyak barang lainnya, ini menyediakan implementasi ForEach yang diharapkan. Anda dapat menulis kode seperti ini:
sumber
Menurut PLINQ (tersedia sejak .Net 4.0), Anda dapat melakukan
untuk melakukan loop foreach paralel pada IEnumerable.
sumber
Tujuan dari ForEach adalah untuk menimbulkan efek samping. IEnumerable adalah untuk enumerasi satu set yang malas.
Perbedaan konseptual ini cukup terlihat ketika Anda mempertimbangkannya.
SomeEnumerable.ForEach(item=>DataStore.Synchronize(item));
Ini tidak akan dijalankan sampai Anda melakukan "menghitung" atau "Daftar ()" atau sesuatu di atasnya. Jelas bukan apa yang diungkapkan.
Anda harus menggunakan ekstensi IEnumerable untuk menyiapkan rantai iterasi, menentukan konten berdasarkan sumber dan ketentuan masing-masing. Pohon Ekspresi kuat dan efisien, tetapi Anda harus belajar untuk menghargai sifat mereka. Dan tidak hanya untuk pemrograman di sekitar mereka untuk menyimpan beberapa karakter yang mengesampingkan evaluasi malas.
sumber
Banyak orang yang menyebutkannya, tetapi saya harus menuliskannya. Bukankah ini paling jelas / paling mudah dibaca?
Singkat dan sederhana.
sumber
GetItems()
metode apa yang dikembalikan.foreach (var item in GetItems()) item.DoStuff();
hanya keindahan.Sekarang kami memiliki opsi untuk ...
Tentu saja, ini membuka kaleng ulat baru.
ps (Maaf tentang font, itu yang diputuskan sistem)
sumber
Seperti yang sudah ditunjukkan oleh banyak jawaban, Anda dapat dengan mudah menambahkan sendiri metode perluasan semacam itu. Namun, jika Anda tidak ingin melakukan itu, meskipun saya tidak mengetahui hal seperti ini di BCL, masih ada opsi di
System
namespace, jika Anda sudah memiliki referensi ke Reactive Extension (dan jika Anda tidak , Kamu harus punya):Meskipun nama metode sedikit berbeda, hasil akhirnya adalah persis apa yang Anda cari.
sumber
ForEach juga dapat Dirantai , cukup kembalikan ke pileline setelah tindakan. tetap fasih
Sebuah Bersemangat versi implementasi.
Edit: a Malas versi menggunakan yield return, seperti ini .
Versi Malas PERLU terwujud, ToList () misalnya, jika tidak, tidak ada yang terjadi. lihat di bawah komentar hebat dari ToolmakerSteve.
Saya menyimpan ForEach () dan ForEachLazy () di perpustakaan saya.
sumber
foreach(T item in enu) {action(item); yield return item;}
foreach (T item in enu) { action1(item); action2(item); action3(item); }
? Lingkaran tunggal, eksplisit,. Saya kira jika itu penting untuk melakukan semua action1 SEBELUM mulai melakukan action2.ProcessShipping()
? Anda mengirim email kepada pembeli, menagih kartu kreditnya, tetapi tidak pernah mengirim barang kepadanya? Pastinya menanyakan masalah.Abstraksi "pendekatan fungsional" ini bocor banyak waktu. Tidak ada pada tingkat bahasa yang mencegah efek samping. Selama Anda bisa membuatnya memanggil lambda / delegasi Anda untuk setiap elemen dalam wadah - Anda akan mendapatkan perilaku "ForEach".
Di sini misalnya satu cara menggabungkan srcDictionary ke destDictionary (jika kunci sudah ada - ditimpa)
ini adalah hack, dan tidak boleh digunakan dalam kode produksi apa pun.
sumber
foreach(var tuple in srcDictionary) { destDictionary[tuple.Key] = tuple.Value; }
? Jika tidak dalam kode produksi di mana dan mengapa Anda harus menggunakan ini?Terinspirasi oleh Jon Skeet, saya telah memperluas solusinya dengan yang berikut:
Metode ekstensi:
Klien:
. . .
sumber
MoreLinq memiliki
IEnumerable<T>.ForEach
dan banyak ekstensi berguna lainnya. Mungkin tidak pantas hanya untuk ketergantunganForEach
, tetapi ada banyak hal berguna di sana.https://www.nuget.org/packages/morelinq/
https://github.com/morelinq/MoreLINQ
sumber
Saya dengan hormat tidak setuju dengan gagasan bahwa metode ekstensi tautan harus bebas efek samping (bukan hanya karena tidak, delegasi mana pun dapat melakukan efek samping).
Pertimbangkan yang berikut ini:
Apa yang ditunjukkan contoh ini adalah benar-benar semacam ikatan yang memungkinkan seseorang memanggil salah satu dari banyak tindakan yang mungkin memiliki efek samping pada urutan elemen, tanpa harus menulis konstruksi saklar besar untuk memecahkan kode nilai yang mendefinisikan tindakan dan menerjemahkan ke dalam metode yang sesuai.
sumber
Agar tetap lancar, seseorang dapat menggunakan trik seperti ini:
sumber
Untuk VB.NET Anda harus menggunakan:
sumber
List
atauIList
. Untuk seorang jenderalIEnumerable
, tulis VB yang setara dengan metode ekstensi ForEach jawaban yang diterima .ForEach
Contoh lain lagisumber