Eric Lippert ha scritto un eccellente serie di articoli sui limiti (e le decisioni di progettazione che influenzano tali scelte) su iterator blocks
In particolare blocchi iteratore sono attuati da alcune trasformazioni di codice compilatore sofisticati. Queste trasformazioni avrebbero un impatto con le trasformazioni che avvengono all'interno di funzioni anonime o lambda in modo tale che in determinate circostanze entrambi tenterebbero di "convertire" il codice in qualche altro costrutto che fosse incompatibile con l'altro.
Di conseguenza sono vietati dall'interazione.
Come i blocchi iteratori funzionano sotto il cofano viene trattato bene here.
Come semplice esempio di un'incompatibilità:
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();
}
Il compilatore viene simultaneamente voler convertire questo in modo seguente:
// 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();
}
e allo stesso tempo l'aspetto iteratore sta cercando di fare è lavoro per fare una piccola macchina statale. Alcuni semplici esempi potrebbero funzionare con una notevole quantità di controllo dell'integrità (prima affrontare i (chiusure eventualmente arbitrariamente nexted) poi vedere se il livello di fondo risultante classi potrebbe essere trasformato in macchine a stati iteratore.
Tuttavia questo sarebbe
- Un sacco di lavoro.
- Potrebbe non funzionare in tutti i casi senza che l'aspetto del blocco iteratore sia in grado di impedire che l'aspetto di chiusura applichi determinate trasformazioni per l'efficienza (come la promozione di variabili locali a variabili di istanza piuttosto che una classe di chiusura completa).
- Se ci fosse anche una piccola possibilità di sovrapposizione in cui era impossibile o sufficientemente difficile non essere attuato allora il numero di problemi di supporto con conseguente sarebbe probabilmente elevata, in quanto la variazione di rottura sottile sarebbe perso su molti utenti.
- Può essere facilmente lavorato.
Nel tuo esempio in questo modo:
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;
}
Ora che possiamo avere anonimi 'lambda async' permettendo' await' interno in C# 5.0, sarei interessato a sapere il motivo per cui ancora rifugio implementare iteratori anonimi con 'yield' inside. Più o meno, è lo stesso generatore di macchine di stato. – Noseratio