Terinspirasi oleh pertanyaan lain yang menanyakan tentang Zip
fungsi yang hilang :
Mengapa tidak ada ForEach
metode ekstensi di Enumerable
kelas? Atau dimana saja? Satu-satunya kelas yang mendapat ForEach
metode adalah List<>
. Apakah ada alasan mengapa itu hilang (kinerja)?
c#
.net
vb.net
extension-methods
Cameron MacFarland
sumber
sumber
Parallel.ForEach
untukEnumerable.ForEach
hanya untuk menemukan kembali yang terakhir tidak ada. C # melewatkan trik untuk mempermudah di sini.Jawaban:
Sudah ada pernyataan pendahuluan termasuk dalam bahasa yang melakukan pekerjaan sebagian besar waktu.
Aku benci melihat yang berikut ini:
Dari pada:
Yang terakhir ini lebih jelas dan lebih mudah dibaca di sebagian besar situasi , meskipun mungkin sedikit lebih lama untuk mengetik.
Namun, saya harus mengakui bahwa saya mengubah pendirian saya tentang masalah itu; metode ekstensi ForEach () memang akan berguna dalam beberapa situasi.
Berikut adalah perbedaan utama antara pernyataan dan metode:
Itu semua adalah poin bagus yang dibuat oleh banyak orang di sini dan saya dapat melihat mengapa orang kehilangan fungsi. Saya tidak keberatan Microsoft menambahkan metode ForEach standar dalam iterasi kerangka kerja berikutnya.
sumber
foreach
adalah tipe yang diperiksa pada waktu kompilasi jika enumerable di-parameterisasi. Itu hanya kurang mengkompilasi tipe waktu memeriksa untuk koleksi non-generik, seperti halnyaForEach
metode ekstensi hipotetis .col.Where(...).OrderBy(...).ForEach(...)
. Sintaksnya jauh lebih sederhana, tidak ada polusi layar dengan variabel lokal berlebihan atau tanda kurung panjang di foreach ().list.ForEach(item => item.DoSomething())
. Dan siapa bilang daftar? Kasus penggunaan yang jelas adalah pada akhir rantai; dengan pernyataan pendahuluan, Anda harus menempatkan seluruh rantai setelahnyain
, dan operasi untuk dilakukan di dalam blok, yang jauh kurang alami atau konsisten.Metode ForEach ditambahkan sebelum LINQ. Jika Anda menambahkan ekstensi ForEach, itu tidak akan pernah dipanggil untuk instance Daftar karena kendala metode ekstensi. Saya pikir alasannya tidak ditambahkan adalah untuk tidak mengganggu yang sudah ada.
Namun, jika Anda benar-benar kehilangan fungsi kecil yang menyenangkan ini, Anda dapat meluncurkan versi Anda sendiri
sumber
Anda dapat menulis metode ekstensi ini:
Pro
Memungkinkan chaining:
Cons
Ini tidak akan benar-benar melakukan apa pun sampai Anda melakukan sesuatu untuk memaksa iterasi. Karena itu, itu tidak boleh disebut
.ForEach()
. Anda bisa menulis.ToList()
di akhir, atau menulis metode ekstensi ini juga:Ini mungkin terlalu signifikan keberangkatan dari perpustakaan C # pengiriman; pembaca yang tidak terbiasa dengan metode ekstensi Anda tidak akan tahu apa yang membuat kode Anda.
sumber
{foreach (var e in source) {action(e);} return source;}
numbers.Select(n => n*2);
Select()
kata menerapkan fungsi ke setiap elemen dan mengembalikan nilai fungsi di manaApply()
mengatakan menerapkan sebuahAction
ke setiap elemen dan mengembalikan elemen asli .Select(e => { action(e); return e; })
Diskusi di sini memberikan jawabannya:
Pada dasarnya keputusan dibuat untuk menjaga metode penyuluhan fungsional "murni". ForEach akan mendorong efek samping saat menggunakan metode ekstensi Enumerable, yang bukan tujuannya.
sumber
Sementara saya setuju bahwa lebih baik menggunakan built-in
Contohforeach
construct dalam banyak kasus, saya menemukan penggunaan variasi ini pada ekstensi <Enach <> menjadi sedikit lebih baik daripada harus mengelola indeks secara teraturforeach
:Akan memberi Anda:
sumber
Salah satu solusinya adalah menulis
.ToList().ForEach(x => ...)
.pro
Mudah dimengerti - pembaca hanya perlu tahu apa yang dikirim dengan C #, bukan metode ekstensi tambahan.
Kebisingan sintaksis sangat ringan (hanya menambahkan sedikit kode tambahan).
Biasanya tidak memerlukan memori ekstra, karena penduduk asli
.ForEach()
harus menyadari seluruh koleksinya.kontra
Urutan operasi tidak ideal. Saya lebih suka menyadari satu elemen, lalu menindaklanjutinya, lalu ulangi. Kode ini menyadari semua elemen terlebih dahulu, kemudian bertindak masing-masing secara berurutan.
Jika menyadari daftar melempar pengecualian, Anda tidak pernah bisa bertindak pada satu elemen.
Jika enumerasi tidak terbatas (seperti angka alami), Anda kurang beruntung.
sumber
Enumerable.ForEach<T>
metode, adaList<T>.ForEach
metode. c) "Biasanya tidak memerlukan memori tambahan, karena asli. Untuk setiap () harus merealisasikan seluruh koleksi, pula." - lengkap dan omong kosong. Berikut ini adalah implementasi dari Enumerable.ForEach <T> yang akan disediakan oleh C # jika itu terjadi:public static void ForEach<T>(this IEnumerable<T> list, Action<T> action) { foreach (T item in list) action(item); }
Saya selalu bertanya-tanya sendiri, itulah sebabnya saya selalu membawa ini:
Metode ekstensi kecil yang bagus.
sumber
Jadi ada banyak komentar tentang fakta bahwa metode ekstensi ForEach tidak tepat karena tidak mengembalikan nilai seperti metode ekstensi LINQ. Meskipun ini adalah pernyataan faktual, itu tidak sepenuhnya benar.
Metode ekstensi LINQ melakukan semua mengembalikan nilai sehingga mereka dapat dirantai bersama:
Namun, hanya karena LINQ diimplementasikan menggunakan metode ekstensi tidak berarti metode ekstensi harus digunakan dengan cara yang sama dan mengembalikan nilai. Menulis metode ekstensi untuk mengekspos fungsionalitas umum yang tidak mengembalikan nilai adalah penggunaan yang benar-benar valid.
Argumen khusus tentang ForEach adalah bahwa, berdasarkan batasan pada metode ekstensi (yaitu bahwa metode ekstensi tidak akan pernah menimpa metode yang diwariskan dengan tanda tangan yang sama ), mungkin ada situasi di mana metode ekstensi kustom tersedia di semua kelas yang menerapkan Tidak dapat dihitung
<T
> kecuali Daftar<T
>. Ini dapat menyebabkan kebingungan ketika metode mulai berperilaku berbeda tergantung pada apakah metode ekstensi atau metode warisan dipanggil.sumber
Anda dapat menggunakan (dapat ditagih, tetapi dievaluasi malas)
Select
, pertama melakukan operasi Anda, dan kemudian mengembalikan identitas (atau sesuatu yang lain jika Anda suka)Anda harus memastikan itu masih dievaluasi, baik dengan
Count()
(operasi termurah untuk menyebutkan afaik) atau operasi lain yang Anda perlukan.Saya ingin melihatnya dibawa ke perpustakaan standar:
Kode di atas kemudian menjadi
people.WithLazySideEffect(p => Console.WriteLine(p))
yang secara efektif setara dengan foreach, tetapi malas dan rantai.sumber
Select
tidak melakukan lagi apa yang seharusnya dilakukan. itu jelas merupakan solusi untuk apa yang diminta OP - tetapi pada keterbacaan topik: tidak seorang pun akan berharap bahwa pemilih menjalankan fungsi.Select
tidak melakukan apa yang seharusnya dilakukan itu adalah masalah dengan implementasiSelect
, bukan dengan kode yang memanggilSelect
, yang tidak memiliki pengaruh terhadap apa yangSelect
dilakukannya.Perhatikan bahwa MoreLINQ NuGet menyediakan
ForEach
metode ekstensi yang Anda cari (sertaPipe
metode yang mengeksekusi delegasi dan menghasilkan hasilnya). Lihat:sumber
@Coincoin
Kekuatan sebenarnya dari metode ekstensi foreach melibatkan penggunaan kembali
Action<>
tanpa menambahkan metode yang tidak perlu ke kode Anda. Katakanlah Anda memiliki 10 daftar dan Anda ingin melakukan logika yang sama pada mereka, dan fungsi yang sesuai tidak masuk ke dalam kelas Anda dan tidak digunakan kembali. Alih-alih memiliki sepuluh untuk loop, atau fungsi generik yang jelas-jelas merupakan helper yang bukan milik, Anda dapat menyimpan semua logika Anda di satu tempat (theAction<>
. Jadi, puluhan baris diganti dengandll ...
Logikanya ada di satu tempat dan Anda belum mencemari kelas Anda.
sumber
f(p)
, kemudian meninggalkan keluar{ }
untuk singkatan:for (var p in List1.Concat(List2).Concat(List2)) f(p);
.Sebagian besar metode ekstensi LINQ mengembalikan hasil. ForEach tidak cocok dengan pola ini karena tidak mengembalikan apa pun.
sumber
public IEnumerable<T> Foreach<T>(this IEnumerable<T> items, Action<T> action) { /* error check */ foreach (var item in items) { action(item); yield return item; } }
Jika Anda memiliki F # (yang akan berada dalam versi .NET berikutnya), Anda dapat menggunakan
Seq.iter doSomething myIEnumerable
sumber
Sebagian karena desainer bahasa tidak setuju dengan itu dari perspektif filosofis.
https://blogs.msdn.microsoft.com/ericlippert/2009/05/18/foreach-vs-foreach/
sumber
Anda dapat menggunakan pilih ketika Anda ingin mengembalikan sesuatu. Jika tidak, Anda dapat menggunakan ToList terlebih dahulu, karena Anda mungkin tidak ingin mengubah apa pun dalam koleksi.
sumber
Saya menulis posting blog tentang hal itu: http://blogs.msdn.com/kirillosenkov/archive/2009/01/31/foreach.aspx
Anda dapat memberikan suara di sini jika Anda ingin melihat metode ini dalam .NET 4.0: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=279093
sumber
Dalam 3.5, semua metode ekstensi ditambahkan ke IEnumerable ada untuk dukungan LINQ (perhatikan bahwa mereka didefinisikan dalam kelas System.Linq.Enumerable). Dalam posting ini, saya menjelaskan mengapa foreach tidak termasuk dalam LINQ: Metode ekstensi LINQ yang ada mirip dengan Parallel.For?
sumber
Apakah saya atau Daftar <T> .Foreach sudah dibuat usang oleh Linq. Awalnya ada
di mana Y hanya harus IEnumerable (Pre 2.0), dan mengimplementasikan GetEnumerator (). Jika Anda melihat MSIL yang dihasilkan, Anda dapat melihat bahwa itu persis sama dengan
(Lihat http://alski.net/post/0a-for-foreach-forFirst-forLast0a-0a-.aspx untuk MSIL)
Kemudian di DotNet2.0 Generik datang dan Daftar. Foreach selalu merasa bagi saya untuk menjadi implementasi dari pola Vistor, (lihat Pola Desain oleh Gamma, Helm, Johnson, Vlissides).
Sekarang tentu saja dalam 3,5 kita bisa menggunakan Lambda untuk efek yang sama, misalnya coba http://dotnet-developments.blogs.techtarget.com/2008/09/02/iterators-lambda-and-linq-oh- saya/
sumber
Saya ingin memperluas jawaban Aku .
Jika Anda ingin memanggil metode dengan tujuan semata-mata untuk efek samping tanpa mengulangi seluruh enumerable terlebih dahulu, Anda dapat menggunakan ini:
sumber
Select(x => { f(x); return x;})
Belum ada yang menunjukkan bahwa ForEach <T> menghasilkan kompilasi jenis waktu memeriksa di mana kata kunci foreach diperiksa runtime.
Setelah melakukan beberapa refactoring di mana kedua metode digunakan dalam kode, saya mendukung. ForEach, karena saya harus memburu kegagalan pengujian / kegagalan runtime untuk menemukan masalah pendahuluan.
sumber
foreach
kompilasi waktu pengecekan kurang. Tentu, jika koleksi Anda adalah IEnumerable non-generik, variabel loop akan menjadiobject
, tetapi hal yang sama akan berlaku untukForEach
metode ekstensi hipotetis .