No mucho tiempo antes de que he descubierto, que la nueva dynamic
palabra clave no funciona bien con el C# 's foreach
declaración:C# 4.0 'dinámico' y sentencia foreach
using System;
sealed class Foo {
public struct FooEnumerator {
int value;
public bool MoveNext() { return true; }
public int Current { get { return value++; } }
}
public FooEnumerator GetEnumerator() {
return new FooEnumerator();
}
static void Main() {
foreach (int x in new Foo()) {
Console.WriteLine(x);
if (x >= 100) break;
}
foreach (int x in (dynamic)new Foo()) { // :)
Console.WriteLine(x);
if (x >= 100) break;
}
}
}
he esperado que la iteración en el dynamic
variable debería funcionar completamente como si el tipo de variable de recopilación se conociera en tiempo de compilación. He descubierto que el segundo bucle en realidad se parece a esto cuando se compila:
foreach (object x in (IEnumerable) /* dynamic cast */ (object) new Foo()) {
...
}
y cada acceso a la x resultados variables con el dinámicas de búsqueda/cast lo que C# ignora que he especificar la correcta x
' s escriba en la declaración de foreach - eso fue un poco sorprendente para mí ... ¡Y también, el compilador de C# ignora por completo que la colección de la variable de tipo dinámico puede implementar la interfaz IEnumerable<T>
!
El comportamiento completo foreach
declaración se describe en la especificación de C# 4.0 8.8.4 La instrucción foreach artículo.
Pero ... ¡Es perfectamente posible implementar el mismo comportamiento en el tiempo de ejecución! Es posible añadir una CSharpBinderFlags.ForEachCast
indicador adicional, corregir el código emmited que se parece a:
foreach (int x in (IEnumerable<int>) /* dynamic cast with the CSharpBinderFlags.ForEachCast flag */ (object) new Foo()) {
...
}
y añadir un poco de lógica adicional para CSharpConvertBinder
:
- Wrap
IEnumerable
colecciones yIEnumerator
's aIEnumerable<T>
/IEnumerator<T>
. - Ajustar colecciones no implementa
Ienumerable<T>
/IEnumerator<T>
para implementar estas interfaces.
Así que hoy foreach
itera sobre dynamic
completamente diferente de la variable de iteración en la colección de forma estática conocida y completamente ignora la información de tipo, especificadas por el usuario. Todo lo que resulta con el comportamiento de iteración diferente (IEnumarble<T>
-implementar colecciones se itera como solo IEnumerable
-implementing) y más de 150x
desaceleración al iterar sobre dynamic
. Solución simple voluntad como resultado un rendimiento mucho mejor:
foreach (int x in (IEnumerable<int>) dynamicVariable) {
Pero por qué debería escribir código como este?
Es muy bien para ver que a veces C# 4.0 dynamic
obras completamente igual si el tipo se conoce en tiempo de compilación, pero es muy triste ver que dynamic
trabajos completamente diferentes en los que puede trabaja el mismo código que estático de tipos .
Así que mi pregunta es: ¿por qué foreach
sobre dynamic
funciona diferente de foreach
sobre cualquier otra cosa?
Me importa mucho el comportamiento, eso es completamente diferente de 'foreach' estático! El problema de rendimiento es solo el resultado de un comportamiento inapropiado. ¿Por qué usar 'IEnumerable' + conversión dinámica donde se sabe estáticamente que' forech' se repetirá sobre la secuencia de enteros? – ControlFlow