1166 votes

Comment obtenez-vous l'indice de l'itération en cours d'une boucle foreach?

Y a-t-il une construction de langage rare que je n'ai pas rencontrée (comme les quelques que j'ai apprises récemment, certaines sur Stack Overflow) en C # pour obtenir une valeur représentant l'itération courante d'une boucle foreach?

Par exemple, je fais actuellement quelque chose comme ça en fonction des circonstances:

 int i=0;
foreach (Object o in collection)
{
    // ...
    i++;
}
 

854voto

bcahill Points 427

Ian Mercer a posté cette solution sur le blog de Phil Haack.

 foreach (var item in Model.Select((value,i) => new {i, value}))
 

Cela vous obtient l'élément (item.value) et son index (item.i).

http://haacked.com/archive/2011/04/14/a-better-razor-foreach-loop.aspx

628voto

FlySwat Points 61945

L' foreach est pour itérer sur les collections de mettre en oeuvre IEnumerable. Il le fait en appelant GetEnumerator sur la collection, qui sera de retour une Enumerator.

Cet agent Recenseur a une méthode et une propriété:

  • MoveNext()
  • Actuel

Current retourne l'objet Énumérateur est actuellement sur, MoveNext mises à jour Current à l'objet suivant.

Évidemment, le concept d'un index est étrangère à la notion de dénombrement, et ne peut pas être fait.

À cause de cela, la plupart des collections sont en mesure d'être parcouru à l'aide d'un indexeur et la construction de boucle pour.

J'ai beaucoup préfèrent à l'aide d'une boucle for dans cette situation par rapport au suivi de l'index avec une variable locale.

125voto

Brad Wilson Points 22910

Pourrait faire quelque chose comme ceci:

 public static class ForEachExtensions
{
    public static void ForEachWithIndex<T>(this IEnumerable<T> enumerable, Action<T, int> handler)
    {
        int idx = 0;
        foreach (T item in enumerable)
            handler(item, idx++);
    }
}

public class Example
{
    public static void Main()
    {
        string[] values = new[] { "foo", "bar", "baz" };

        values.ForEachWithIndex((item, idx) => Console.WriteLine("{0}: {1}", idx, item));
    }
}
 

109voto

mike nelson Points 3819

Je suis en désaccord avec les commentaires que l' for boucle est un meilleur choix dans la plupart des cas.

foreach construction est utile, et pas replaceble par un for boucle dans toutes les circonstances.

Par exemple, si vous avez un DataReader et boucle à travers tous les enregistrements à l'aide d'un foreach il appelle automatiquement le Jeter méthode et ferme le lecteur (qui peut alors fermer la connexion automatiquement). C'est donc plus sûr, car il empêche les fuites sur les conduites, même si vous oubliez de fermer le lecteur.

(Assurez-vous qu'il est de bonne pratique de toujours fermer les lecteurs, mais le compilateur n'est pas de l'attraper si vous ne - vous ne pouvez pas garantir que vous avez fermé tous les lecteurs, mais vous pouvez la rendre plus probable que vous n'aurez pas de fuite de connexions, prenez l'habitude d'utiliser un foreach.)

Il peut y avoir d'autres exemples de l'appel implicite de l' Dispose méthode utile.

68voto

David B Points 53123

Réponse littérale - avertissement, les performances peuvent ne pas être aussi bonnes que l'utilisation d'un int pour suivre l'index. Au moins, c'est mieux que d'utiliser IndexOf .

Vous avez juste besoin d'utiliser la surcharge d'indexation de Select pour envelopper chaque élément de la collection avec un objet anonyme qui connaît l'index. Cela peut être fait contre tout ce qui implémente IEnumerable.

 System.Collections.IEnumerable collection = Enumerable.Range(100, 10);

foreach (var o in collection.OfType<object>().Select((x, i) => new {x, i}))
{
    Console.WriteLine("{0} {1}", o.i, o.x);
}
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X