Saya pikir alangkah baiknya melakukan sesuatu seperti ini (dengan lambda melakukan pengembalian hasil):
public IList<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, new()
{
IList<T> list = GetList<T>();
var fun = expression.Compile();
var items = () => {
foreach (var item in list)
if (fun.Invoke(item))
yield return item; // This is not allowed by C#
}
return items.ToList();
}
Namun, saya menemukan bahwa saya tidak dapat menggunakan hasil dalam metode anonim. Saya bertanya-tanya mengapa. Dokumen hasil hanya mengatakan itu tidak diizinkan.
Karena tidak diizinkan, saya baru saja membuat Daftar dan menambahkan item ke dalamnya.
c#
yield
anonymous-methods
yield-return
Lance Fisher
sumber
sumber
async
lambda anonim yang memungkinkanawait
di dalam C # 5.0, saya tertarik untuk mengetahui mengapa mereka masih belum menerapkan iterator anonim denganyield
di dalamnya. Kurang lebih, itu adalah generator mesin negara yang sama.Jawaban:
Eric Lippert baru-baru ini menulis serangkaian postingan blog tentang mengapa penghasilan tidak diizinkan dalam beberapa kasus.
EDIT2:
Anda mungkin akan menemukan jawabannya di sana ...
EDIT1: ini dijelaskan dalam komentar di Bagian 5, dalam jawaban Eric atas komentar Abhijeet Patel:
Q:
SEBUAH :
sumber
Eric Lippert telah menulis serangkaian artikel yang sangat bagus tentang batasan (dan keputusan desain yang memengaruhi pilihan tersebut) di blok iterator
Secara khusus, blok iterator diimplementasikan oleh beberapa transformasi kode kompilator yang canggih. Transformasi ini akan berdampak dengan transformasi yang terjadi di dalam fungsi anonim atau lambda sedemikian rupa sehingga dalam keadaan tertentu mereka berdua akan mencoba untuk 'mengubah' kode menjadi beberapa konstruksi lain yang tidak kompatibel dengan yang lain.
Akibatnya mereka dilarang berinteraksi.
Bagaimana blok iterator bekerja di bawah kap ditangani dengan baik di sini .
Sebagai contoh sederhana dari ketidakcocokan:
public IList<T> GreaterThan<T>(T t) { IList<T> list = GetList<T>(); var items = () => { foreach (var item in list) if (fun.Invoke(item)) yield return item; // This is not allowed by C# } return items.ToList(); }
Kompiler secara bersamaan ingin mengubah ini menjadi seperti:
// inner class private class Magic { private T t; private IList<T> list; private Magic(List<T> list, T t) { this.list = list; this.t = t;} public IEnumerable<T> DoIt() { var items = () => { foreach (var item in list) if (fun.Invoke(item)) yield return item; } } } public IList<T> GreaterThan<T>(T t) { var magic = new Magic(GetList<T>(), t) var items = magic.DoIt(); return items.ToList(); }
dan pada saat yang sama aspek iterator mencoba melakukan pekerjaannya untuk membuat mesin status kecil. Contoh sederhana tertentu mungkin bekerja dengan cukup banyak pemeriksaan kewarasan (pertama berurusan dengan penutupan bersarang (mungkin sewenang-wenang) kemudian melihat apakah kelas yang dihasilkan tingkat paling bawah dapat diubah menjadi mesin negara iterator.
Bagaimanapun ini akan terjadi
Dalam contoh Anda seperti ini:
public IList<T> Find<T>(Expression<Func<T, bool>> expression) where T : class, new() { return FindInner(expression).ToList(); } private IEnumerable<T> FindInner<T>(Expression<Func<T, bool>> expression) where T : class, new() { IList<T> list = GetList<T>(); var fun = expression.Compile(); foreach (var item in list) if (fun.Invoke(item)) yield return item; }
sumber
Magic
seharusnya kelasmuMagic<T>
.Sayangnya saya tidak tahu mengapa mereka tidak mengizinkan ini, karena tentu saja sangat mungkin untuk membayangkan bagaimana ini akan bekerja.
Namun, metode anonim sudah menjadi bagian dari "sihir kompilator" dalam arti bahwa metode tersebut akan diekstraksi baik ke metode di kelas yang ada, atau bahkan ke kelas yang sama sekali baru, tergantung pada apakah ia berurusan dengan variabel lokal atau tidak.
Selain itu, penggunaan metode iterator
yield
juga diimplementasikan menggunakan sihir kompilator.Dugaan saya adalah bahwa salah satu dari keduanya membuat kode tidak dapat diidentifikasi ke bagian sihir lainnya, dan diputuskan untuk tidak menghabiskan waktu untuk membuat ini berfungsi untuk versi kompiler C # saat ini. Tentu saja, ini mungkin bukan pilihan yang sadar sama sekali, dan itu tidak berhasil karena tidak ada yang berpikir untuk menerapkannya.
Untuk pertanyaan akurat 100%, saya sarankan Anda menggunakan situs Microsoft Connect dan melaporkan pertanyaan, saya yakin Anda akan mendapatkan sesuatu yang dapat digunakan sebagai gantinya.
sumber
Saya akan melakukan ini:
IList<T> list = GetList<T>(); var fun = expression.Compile(); return list.Where(item => fun.Invoke(item)).ToList();
Tentu saja Anda memerlukan System.Core.dll yang dirujuk dari .NET 3.5 untuk metode Linq. Dan termasuk:
using System.Linq;
Bersulang,
Licik
sumber
Mungkin itu hanya batasan sintaks. Dalam Visual Basic .NET, yang sangat mirip dengan C #, sangat mungkin ketika menulis dengan canggung
Sub Main() Console.Write("x: ") Dim x = CInt(Console.ReadLine()) For Each elem In Iterator Function() Dim i = x Do Yield i i += 1 x -= 1 Loop Until i = x + 20 End Function() Console.WriteLine($"{elem} to {x}") Next Console.ReadKey() End Sub
Perhatikan juga tanda kurung
' here
; fungsi lambdaIterator Function
...End Function
mengembalikan sebuahIEnumerable(Of Integer)
tapi tidak seperti objek itu sendiri. Itu harus dipanggil untuk mendapatkan benda itu.Kode yang diubah oleh [1] menimbulkan kesalahan di C # 7.3 (CS0149):
static void Main() { Console.Write("x: "); var x = System.Convert.ToInt32(Console.ReadLine()); // ERROR: CS0149 - Method name expected foreach (var elem in () => { var i = x; do { yield return i; i += 1; x -= 1; } while (!i == x + 20); }()) Console.WriteLine($"{elem} to {x}"); Console.ReadKey(); }
Saya sangat tidak setuju dengan alasan yang diberikan dalam jawaban lain bahwa sulit untuk ditangani oleh compiler. Yang
Iterator Function()
Anda lihat di contoh VB.NET secara khusus dibuat untuk iterator lambda.Di VB, ada
Iterator
kata kunci; itu tidak memiliki mitra C #. IMHO, tidak ada alasan sebenarnya ini bukan fitur C #.Jadi jika Anda benar-benar menginginkan fungsi iterator anonim, saat ini gunakan Visual Basic atau (saya belum memeriksanya) F #, seperti yang dinyatakan dalam komentar Bagian # 7 dalam jawaban @Thomas Levesque (lakukan Ctrl + F untuk F #).
sumber