En C #, ¿cómo se obtiene un enumerador genérico de una matriz determinada?
En el código siguiente, MyArray
hay una matriz de MyType
objetos. Me gustaría obtener MyIEnumerator
de la manera que se muestra, pero parece que obtengo un enumerador vacío (aunque lo he confirmado MyArray.Length > 0
).
MyType[] MyArray = ... ;
IEnumerator<MyType> MyIEnumerator = MyArray.GetEnumerator() as IEnumerator<MyType>;
c#
arrays
generics
ienumerator
JaysonFix
fuente
fuente
Respuestas:
Funciona en 2.0+:
Funciona en 3.5+ (LINQy elegante, un poco menos eficiente):
fuente
LINQ/Cast
tiene un comportamiento en tiempo de ejecución bastante diferente, ya que todos y cada uno de los elementos de la matriz se pasarán a través de un conjunto adicional de recorridos de idaMoveNext
yCurrent
vuelta de enumeradores, y esto podría afectar el rendimiento si la matriz es enorme. En cualquier caso, el problema se evita completa y fácilmente al obtener el enumerador adecuado en primer lugar (es decir, utilizando uno de los dos métodos que se muestran en mi respuesta).myArray.Cast<MyType>().GetEnumerator()
en su bucle más interno, puede ralentizarlo significativamente incluso para matrices pequeñas.Puedes decidir por ti mismo si la transmisión es lo suficientemente fea como para justificar una llamada ajena a la biblioteca:
Y para completar, también se debe tener en cuenta que lo siguiente no es correcto, y se bloqueará en tiempo de ejecución, porque
T[]
elige la interfaz no genéricaIEnumerable
para su implementación predeterminada (es decir, no explícita) deGetEnumerator()
.El misterio es, ¿por qué no
SZGenericArrayEnumerator<T>
hereda deSZArrayEnumerator
una clase interna que actualmente está marcada como 'sellada', ya que esto permitiría que el enumerador genérico (covariante) se devuelva de forma predeterminada?fuente
((IEnumerable<int>)arr)
pero solo un juego de corchetes adentro(IEnumerator<int>)arr
?Como no me gusta el casting, una pequeña actualización:
fuente
your_array.AsEnumerable()
, no se compilaría en primer lugar, yaAsEnumerable()
que solo se puede usar en instancias de tipos que implementanIEnumerable
.Para hacerlo lo más limpio posible, me gusta dejar que el compilador haga todo el trabajo. No hay yesos (por lo que en realidad es seguro para tipos). No se utilizan bibliotecas de terceros (System.Linq) (sin sobrecarga de tiempo de ejecución).
// Y para usar el código:
Esto aprovecha la magia del compilador que mantiene todo limpio.
El otro punto a tener en cuenta es que mi respuesta es la única respuesta que realizará la verificación en tiempo de compilación.
Para cualquiera de las otras soluciones, si el tipo de "arr" cambia, el código de llamada se compilará y fallará en tiempo de ejecución, lo que resultará en un error de ejecución.
Mi respuesta hará que el código no se compile y, por lo tanto, tengo menos posibilidades de enviar un error en mi código, ya que me indicaría que estoy usando el tipo incorrecto.
fuente
Foo[]
implementaIEnumerable<Foo>
, pero si eso alguna vez cambia, no se detectará en tiempo de compilación. Las conversiones explícitas nunca son a prueba de tiempo de compilación. En su lugar, asigne / devuelva una matriz como IEnumerable <Foo> usa la conversión implícita que es a prueba de tiempo de compilación.var foo = (int)new object()
. Se compila bien y se bloquea en tiempo de ejecución.YourArray.OfType (). GetEnumerator ();
Puede que funcione un poco mejor, ya que solo hay que comprobar el tipo y no lanzar.
fuente
OfType<..type..>()
double[][]
fuente
Lo que puede hacer, por supuesto, es implementar su propio enumerador genérico para matrices.
Esto es más o menos igual a la implementación .NET de SZGenericArrayEnumerator <T> como lo menciona Glenn Slayden. Por supuesto, solo debe hacer esto, en los casos en que valga la pena el esfuerzo. En la mayoría de los casos no lo es.
fuente