En C #, comment obtenir un énumérateur générique à partir d'un tableau donné?
Dans le code ci-dessous, se MyArray
trouve un tableau d' MyType
objets. Je voudrais obtenir MyIEnumerator
de la manière indiquée, mais il semble que j'obtienne un énumérateur vide (bien que je l'ai confirmé MyArray.Length > 0
).
MyType[] MyArray = ... ;
IEnumerator<MyType> MyIEnumerator = MyArray.GetEnumerator() as IEnumerator<MyType>;
c#
arrays
generics
ienumerator
JaysonFix
la source
la source
Réponses:
Fonctionne sur 2.0+:
Fonctionne sur 3.5+ (fantaisie LINQy, un peu moins efficace):
la source
LINQ/Cast
a un comportement d'exécution tout à fait différent, puisque chaque élément du tableau sera passé à travers un jeu supplémentaire deMoveNext
etCurrent
allers-retours-recenseur, et cela pourrait affecter les performances si le tableau est énorme. Dans tous les cas, le problème est complètement et facilement évité en obtenant le bon énumérateur en premier lieu (c'est-à-dire en utilisant l'une des deux méthodes indiquées dans ma réponse).myArray.Cast<MyType>().GetEnumerator()
dans votre boucle la plus interne, cela peut vous ralentir considérablement, même pour de minuscules tableaux.Vous pouvez décider vous-même si la diffusion est assez moche pour justifier un appel de bibliothèque superflu:
Et pour être complet, il faut également noter que ce qui suit n'est pas correct - et plantera à l'exécution - car
T[]
choisit l' interface non génériqueIEnumerable
pour son implémentation par défaut (c'est-à-dire non explicite) deGetEnumerator()
.Le mystère est, pourquoi
SZGenericArrayEnumerator<T>
n'hérite pas deSZArrayEnumerator
--une classe interne qui est actuellement marquée «scellée» - puisque cela permettrait à l'énumérateur générique (covariant) d'être retourné par défaut?la source
((IEnumerable<int>)arr)
un seul jeu de parenthèses(IEnumerator<int>)arr
?Puisque je n'aime pas le casting, une petite mise à jour:
la source
your_array.AsEnumerable()
, ne compilerait pas en premier lieu carAsEnumerable()
il ne peut être utilisé que sur les instances de types qui implémententIEnumerable
.Pour le rendre aussi propre que possible, j'aime laisser le compilateur faire tout le travail. Il n'y a pas de moulages (donc c'est en fait sûr de type). Aucune bibliothèque tierce (System.Linq) n'est utilisée (aucune surcharge d'exécution).
// Et pour utiliser le code:
Cela tire parti de la magie du compilateur qui garde tout propre.
L'autre point à noter est que ma réponse est la seule réponse qui fera une vérification au moment de la compilation.
Pour toutes les autres solutions, si le type de "arr" change, alors le code d'appel sera compilé et échouera à l'exécution, ce qui provoquera un bogue d'exécution.
Ma réponse fera que le code ne se compilera pas et donc j'ai moins de chance d'envoyer un bogue dans mon code, car cela me signifierait que j'utilise le mauvais type.
la source
Foo[]
implémenteIEnumerable<Foo>
, mais si cela change jamais, il ne sera pas détecté au moment de la compilation. Les transtypages explicites ne sont jamais à l'épreuve de la compilation. Au lieu de cela, attribuer / renvoyer le tableau en tant que IEnumerable <Foo> utilise le cast implicite qui est une preuve à la compilation.var foo = (int)new object()
. Il se compile très bien et plante au moment de l'exécution.YourArray.OfType (). GetEnumerator ();
peut fonctionner un peu mieux, car il suffit de vérifier le type et non de lancer.
la source
OfType<..type..>()
- au moins dans mon cas dedouble[][]
la source
Ce que vous pouvez faire, bien sûr, c'est simplement implémenter votre propre énumérateur générique pour les tableaux.
C'est plus ou moins égal à l'implémentation .NET de SZGenericArrayEnumerator <T> comme mentionné par Glenn Slayden. Vous ne devriez bien sûr le faire que dans les cas où cela en vaut la peine. Dans la plupart des cas, ce n'est pas le cas.
la source