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;
}
return items.ToList();
}
Kompiler secara bersamaan ingin mengubah ini menjadi seperti:
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
- Cukup banyak pekerjaan.
- Tidak mungkin bekerja di semua kasus tanpa setidaknya aspek blok iterator mampu mencegah aspek closure menerapkan transformasi tertentu untuk efisiensi (seperti mempromosikan variabel lokal ke variabel instan daripada kelas closure yang lengkap).
- Jika ada sedikit kemungkinan tumpang tindih di mana tidak mungkin atau cukup sulit untuk tidak diterapkan, maka jumlah masalah dukungan yang dihasilkan kemungkinan besar akan tinggi karena perubahan pemutusan yang halus akan hilang pada banyak pengguna.
- Ini bisa sangat mudah dikerjakan.
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;
}
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.