Eric Lippert ha escrito una excelente serie de artículos sobre las limitaciones (y las decisiones de diseño que influyen en esas decisiones) en iterator blocks
En particular, los bloques de iterador son implementados por algunas transformaciones de código de compilador sofisticados. Estas transformaciones impactarían con las transformaciones que ocurren dentro de las funciones anónimas o lambdas de tal manera que en ciertas circunstancias ambos tratarían de "convertir" el código en algún otro constructo que fuera incompatible con el otro.
Como resultado, están prohibidas las interacciones.
Cómo se tratan los bloques de iteradores bajo el capó bien here.
Como un ejemplo simple de una incompatibilidad:
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();
}
El compilador es querer al mismo tiempo para convertir esto en algo así como:
// 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();
}
y al mismo tiempo el aspecto iterador está tratando de hacer es trabajo hacer una pequeña máquina de estados. Ciertos ejemplos simples pueden funcionar con una buena cantidad de cordura de control (primera trata de los (cierres posiblemente arbitraria nexted) luego ver si el nivel muy inferior resultante clases podría transformarse en máquinas de estado de iterador.
Sin embargo, esto sería
- Mucho trabajo.
- No podría funcionar en todos los casos sin que el aspecto del bloque iterador sea capaz de evitar que el aspecto de cierre aplique ciertas transformaciones para la eficiencia (como promover variables locales a variables de instancia en lugar de una clase de cierre completa).
- Si hubo incluso una ligera posibilidad de solapamiento donde era imposible o no lo suficientemente duro para ser implementado a continuación, el número de problemas de soporte resultantes serían probablemente alta ya que el cambio sutil de ruptura se perdería en muchos usuarios.
- Puede ser muy fácil de trabajar alrededor.
En su ejemplo, así:
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;
}
Ahora que podemos tener lambdas '' async' anónimos permitiendo await' interior en C# 5.0, estaría interesado en saber por qué todavía paraíso 'implementado iteradores anónimos con' rendimiento 'dentro. Más o menos, es el mismo generador de máquina de estado. – Noseratio