IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C# Discussion :

Differences entre foreach et enumerator


Sujet :

C#

  1. #1
    Membre averti Avatar de Contrec
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38

    Informations forums :
    Inscription : Mars 2005
    Messages : 597
    Points : 342
    Points
    342
    Par défaut Differences entre foreach et enumerator
    Bonjour,

    J'aimerai savoir si qulequ'un connait la difference entre un foreach et un enumerator. Afin de parcourir des collections, j'utilise 2 genres de methodes:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    IEnumerator EnumDataRows = this.dS_Parameter.T_PARAMETER.Rows.GetEnumerator();
     
    while (EnumDataRows.MoveNext())
    {
        LMA_DataSets.DS_Parameter.T_PARAMETERRow MyRow = (LMA_DataSets.DS_Parameter.T_PARAMETERRow)EnumDataRows.Current;
     
        MessageBox.Show(MyRow.PARAMETER_NAME);
     
    }

    Ou alors:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    foreach (DataGridViewRow MyRow in this.dgv_Parameters.Rows)
    {
        if (MyRow.IsNewRow == false)
        {
            CurrentSeqNo++;
            RowsToRenumber.Add(MyRow.Cells["PARAMETER_ID"].Value, CurrentSeqNo);
        }
    }
    Quelle est la meilleure solution en termes de rapidite et de securite selon vous ?
    Contrec

  2. #2
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    L'énumérateur te permet de faire des choses un peu casse-pieds à programmer avec le foreach; par exemple examiner une n-ième valeur et en fonction de celle ci déterminer quel comportement devra avoir ta routine avec la n+1-ième, puis lire la n+1-ième.

    Mais les deux bouts de code que tu postes sont équivalent. A priori, je pense que le foreach est peut être un chouia plus performant, mais je ne me suis jamais posé la question en ces termes, plutôt dans le sens inverse : je ne peux pas - ou difficilement- faire avec foreach, ergo je fais avec Enumerator.

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  3. #3
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 277
    Points : 1 521
    Points
    1 521
    Par défaut
    A mon avis, il faut un IEnumerator pour utiliser foreach.

    En effet, lorsqu'on crée une classe collection de A à Z et pour pouvoir utiliser foreach, il faut que la classe implémente IEnumerable qui nécessite l'implémentation de IEnumerator GetEnumerator().

  4. #4
    Inactif  
    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Janvier 2007
    Messages
    6 604
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Points : 13 314
    Points
    13 314
    Par défaut
    Citation Envoyé par Kaidan Voir le message
    A mon avis, il faut un IEnumerator pour utiliser foreach.

    Il est clair qu'en interne, c'est ce qu'il utilise; mais de là à dire que c'est plus performant de l'appeler explicitement, je ne sais pas.

    Je ne réponds pas aux questions techniques par MP ! Le forum est là pour ça...


    Une réponse vous a aidé ? utiliser le bouton

    "L’ennui dans ce monde, c’est que les idiots sont sûrs d’eux et les gens sensés pleins de doutes". B. Russel

  5. #5
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 277
    Points : 1 521
    Points
    1 521
    Par défaut
    Il suffirait de regarder le MSIL, mais à mon avis, le compilateur traduit foreach en while.

  6. #6
    Membre averti Avatar de Contrec
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38

    Informations forums :
    Inscription : Mars 2005
    Messages : 597
    Points : 342
    Points
    342
    Par défaut
    Donc le foreach utilise l'enumerator implicitement...

    Conclusion ?
    Contrec

  7. #7
    Membre expérimenté
    Homme Profil pro
    Inscrit en
    Juillet 2007
    Messages
    1 277
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Réunion

    Informations forums :
    Inscription : Juillet 2007
    Messages : 1 277
    Points : 1 521
    Points
    1 521
    Par défaut
    Conclusion, tu utilises un Stopwatch pour mesurer le temps que prend 100000 itérations de ton code et tu regardes lequel est plus rapide

    Mais à mon avis, c'est quasi-identique.

  8. #8
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2005
    Messages : 700
    Points : 780
    Points
    780
    Par défaut
    Citation Envoyé par Contrec Voir le message
    Conclusion ?
    Ca dépend du besoin :
    si tu va appliquer un traitement à tous donc (pour chaque..) autant utiliser un foreach qui est clair et compris par tous à la premiere lecture...

    Si tu as besoin de parcourir la collection pour t'arreter à l'une d'elle / certaines spécifiquement, ou cycliquement, tu ne peux que la parcourir toi meme...

    Pour la différence de perf, je doute qu'il y ai une véritable différence, puisque derriere un foreach il utilisera l'enum de la même façon...
    Ce n'est pas le parcourt d'une collection qui pénalisera les perfs, mais l'algo que tu appliqueras à ceux qui t'intéressent....

    Enfin bref, je pense qu'il est plus important de bien choisir sa collection en fonction de son besoin, plutôt que de se demander si son parcourt sera plus rapide de cette façon là ou de l'autre...

  9. #9
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    Citation Envoyé par Chubyone Voir le message
    Ca dépend du besoin :
    si tu va appliquer un traitement à tous donc (pour chaque..) autant utiliser un foreach qui est clair et compris par tous à la premiere lecture...

    Si tu as besoin de parcourir la collection pour t'arreter à l'une d'elle / certaines spécifiquement, ou cycliquement, tu ne peux que la parcourir toi meme...
    Bah ? je croyais que break fonctionnait aussi avec foreach ?

    De mon point de vue, l'intérêt principal du foreach, c'est qu'il encapsule des comportements différents en fonction du type de collection derrière une syntaxe simple et unique. On peut faire un foreach sur un int[], sur un List<int>, sur un IEnumerable<int> avec un truc à base de yield return ; on peut ignorer la machinerie interne à la collection, comme les itérateurs c++. Même le c++, qui malgré tout le respect que j'ai pour lui est pas des plus accessibles, a essayé d'uniformiser le parcours des ensembles par une syntaxe à peu près unique.

    foreach, c'est bien Même s'il doit arriver ponctuellement que ça soit plus rapide de faire un MoveNext à la mano.
    ಠ_ಠ

  10. #10
    Membre régulier Avatar de maitredede
    Homme Profil pro
    Pisseur de code
    Inscrit en
    Mai 2006
    Messages
    59
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Nouvelle-Calédonie

    Informations professionnelles :
    Activité : Pisseur de code

    Informations forums :
    Inscription : Mai 2006
    Messages : 59
    Points : 106
    Points
    106
    Par défaut
    Le foreach, c'est bien.

    Après, j'ai lu un article ya pas si longtemps qui comparait les performances entre un foreach, et une boucle type for(int i=0;i<count;i++).
    Le foreach est beaucoup plus lent que le for.

    Perso, les perfs, c'est bien d'y penser, mais si il faut modifier tout un programme pour gagner un pouillème, ça sert à rien. Mon avis, c'est que chacun fait comme il le sent, puisqu'on a le choix.

  11. #11
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2005
    Messages : 700
    Points : 780
    Points
    780
    Par défaut
    Right pour le break, comme le return, yield return, etc...

    La puissance du foreach, c'est qu'il s'appuie sur IEnumerable...
    Et justement, int[] = System.Array, lui meme hérite de IEnumerable...

    C'est vraiment puissant .Net!....


    Donc bon, si tu veux vraiment des perfs de ouf, bein tu peux faire un tableau de pointeurs en compilant en unsafe, et le parcourir en downto0... Je pense que là tu sera plus rapide...

  12. #12
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    Citation Envoyé par Chubyone Voir le message
    Right pour le break, comme le return, yield return, etc...

    La puissance du foreach, c'est qu'il s'appuie sur IEnumerable...
    Et justement, int[] = System.Array, lui meme hérite de IEnumerable...

    C'est vraiment puissant .Net!....
    C'est même plus puissant que ça : foreach ne traite pas tous les énumerables de la même façon, comme montré ici pour les machin[] : http://www.csharphelp.com/archives4/archive690.html
    Reste à savoir si cette optimisation est aussi vraie quand un int[] est connu du foreach seulement en tant que IEnumerable<int>.

    Et pour les perfs :
    http://blogs.msdn.com/kevin_ransom/a...19/116072.aspx
    sur un machin[], for et foreach génèrent le même code IL.
    ಠ_ಠ

  13. #13
    Membre éclairé
    Profil pro
    Inscrit en
    Juillet 2005
    Messages
    700
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Juillet 2005
    Messages : 700
    Points : 780
    Points
    780
    Par défaut
    Merci pour la lecture

    Bon, plus personne ici ne doutera du bienfait de notre ami foreach maintenant, je pense...


    Enfin, on attend toujours tes tests de perf entre les deux, Contrec

  14. #14
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    Après quelques lecture sur le web, il ressort tout de même que faire foreach sur un IEnumerable qui ne peut être déterminé statiquement comme un machin[] passe par l'énumérateur, en faisant un try {} catch {} pour l'acquérir. Dans certains scénarios où le coût d'un try est prohibitif, on pourrait donc préférer MoveNext, mais la plupart du temps on s'en fiche
    ಠ_ಠ

  15. #15
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Points : 5 195
    Points
    5 195
    Par défaut
    salut

    j'ai fait le test suivant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    private void button1_Click(object sender, EventArgs e)
            {
                ml.Clear();
     
                for (int i = 0; i < 1000000; i++)
                {
                    Toto item = new Toto();
                    item.Name = "nico_" + i.ToString();
                    item.Age = 2;
                    ml.Add(item);
                }
     
                string a = string.Empty;
                long res = 0;
                Stopwatch watch = new Stopwatch();
                watch.Start();
                foreach (Toto t in ml)
                {
                    res += t.Age;
                }
     
                watch.Stop();
                Trace.WriteLine("elapsed with Foreach = " + watch.Elapsed.ToString());
                watch.Reset();
                res = 0;
                watch.Start();
     
                int count = ml.Count;
     
                for (int i = 0; i < count; i++)
                {
                    res += ml[i].Age;
                }
     
                watch.Stop();
                Trace.WriteLine("elapsed with For= " + watch.Elapsed.ToString());
     
                watch.Reset();
                res = 0;
                watch.Start();
     
                IEnumerator ie = ml.GetEnumerator();
                while (ie.MoveNext())
                {
                    res+= ((Toto)ie.Current).Age;
                }
     
                watch.Stop();
                Trace.WriteLine("elapsed with IEnumerator = " + watch.Elapsed.ToString());
     
            }
    ou Toto est defini comme

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public struct Toto
        {
            private string name;
            private int age;
     
            public int Age
            {
                get { return age; }
                set { age = value; }
            }
     
            public string Name
            {
                get { return name; }
                set { name = value; }
            }
     
        }
    Voici les resultats sur ma machine en Release :

    Portable HP : Proc 1.73 Ghz Ram 1 Go

    elapsed with Foreach = 00:00:00.0486056
    elapsed with For= 00:00:00.0396902
    elapsed with IEnumerator = 00:00:00.2896264

    On constate "clairement" que le For est un peu plus rapide... Par contre,
    l'énumération (sur une itération de 1000000 d'élément, ca rame sec

    Voila...

    The Monz, Toulouse
    The Monz, Toulouse
    Expertise dans la logistique et le développement pour
    plateforme .Net (Windows, Windows CE, Android)

  16. #16
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Points : 5 195
    Points
    5 195
    Par défaut
    Re

    J'ajouterais que dans le ForEach, on ne peut pas "affecter" et modifier
    la valeure en cours...

    Alors, que dans un For on peut très bien le faire

    Genre

    for(int i = 0 ; i < ....)
    {
    malist[i] = new object(....);
    }

    The Monz, Toulouse
    The Monz, Toulouse
    Expertise dans la logistique et le développement pour
    plateforme .Net (Windows, Windows CE, Android)

  17. #17
    Membre émérite Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Points : 2 925
    Points
    2 925
    Par défaut
    Il est normal que ta version avec énumérateur soit lente, puisque tu es obligé de caster. De plus, ta liste contient une struct ; le compilo est obligé de boxer / déboxer Tu devrais réessayer avec des class au lieu de structs, ou bien voir si on peut récupérer un énumérateur typé (pas vérifié, mais ça doit être possible)
    ಠ_ಠ

  18. #18
    Expert confirmé

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Septembre 2006
    Messages
    3 580
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Septembre 2006
    Messages : 3 580
    Points : 5 195
    Points
    5 195
    Par défaut
    salut

    elapsed with Foreach = 00:00:00.0423824
    elapsed with For= 00:00:00.0388499
    elapsed with IEnumerator = 00:00:00.0613480

    en mettant une classe à la place d'une struct

    The Monz, Toulouse
    The Monz, Toulouse
    Expertise dans la logistique et le développement pour
    plateforme .Net (Windows, Windows CE, Android)

  19. #19
    Membre averti Avatar de Contrec
    Homme Profil pro
    Inscrit en
    Mars 2005
    Messages
    597
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38

    Informations forums :
    Inscription : Mars 2005
    Messages : 597
    Points : 342
    Points
    342
    Par défaut
    Niquel, je pensais que c'etatit l'enumerator qui allait plus vite...
    Contrec

  20. #20
    Membre averti Avatar de npuzin
    Profil pro
    Inscrit en
    Novembre 2007
    Messages
    265
    Détails du profil
    Informations personnelles :
    Âge : 44
    Localisation : Suisse

    Informations forums :
    Inscription : Novembre 2007
    Messages : 265
    Points : 423
    Points
    423
    Par défaut
    Citation Envoyé par maitredede Voir le message
    Le foreach, c'est bien.
    Perso, les perfs, c'est bien d'y penser, mais si il faut modifier tout un programme pour gagner un pouillème, ça sert à rien. Mon avis, c'est que chacun fait comme il le sent, puisqu'on a le choix.
    Effectivement je pense que ce genre d'optimisation est d'un autre temps. La où généralement tu peux gagner un temps significatif avec des optimisations ce sont sur les accès disques éventuellement mais surtout sur les accès réseaux (genre requêtes HTTP ou SQL).

    Si tu as un ping de 0.33s entre ton client et ton serveur tu fais 3 requetes et tu as deja un temps de reponse d'une seconde. Ton pouilleme sera le cadet de tes soucis.

    Pour moi le foreach est un raccourci de langage sur l'autre syntaxe. Je ne vois pas vraiment d'intérêt à utiliser l'autre syntaxe.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Différences entre Delphi et Visual Basic ?
    Par Anonymous dans le forum Débats sur le développement - Le Best Of
    Réponses: 75
    Dernier message: 30/03/2009, 21h09
  2. La difference entre XSL et XSLT?
    Par pantin dans le forum XSL/XSLT/XPATH
    Réponses: 3
    Dernier message: 27/06/2003, 16h14
  3. Difference entre fenetre et boite de dialog
    Par billyboy dans le forum Windows
    Réponses: 2
    Dernier message: 02/06/2003, 16h43
  4. [] Difference entre MSHFlexGrid et MSFlexGrid
    Par olivierx dans le forum VB 6 et antérieur
    Réponses: 6
    Dernier message: 23/04/2003, 09h48
  5. Difference entre types d'Adresse IP
    Par freud dans le forum Développement
    Réponses: 3
    Dernier message: 02/03/2003, 03h06

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo