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 :

boucle, cast et performances


Sujet :

C#

  1. #1
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut boucle, cast et performances
    Bonjour,

    Imaginons que j'ai une classe Mere, ainsi qu'une classe Fille qui herite de Mere.
    Maintenant j'ai une collection de Mere, qui contient des Mere et des Fille.
    Et je voudrais effectuer un traitement sur chaque element de cette collection mais seulement sur les objets de type Fille.

    Un exemple concret: j'ai une classe MyControlType qui herite de Control.
    Ma Form possede une collection de Control, dans lequel j'insere des MyControlType, mais qui possede egalement des controles "normaux" (boutons etc.). Et je voudrais faire une boucle sur Controls, de facon a appeler une fonction DoSomething() de MyControlType. Pour l'instant, j'ai le code suivant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    foreach (Control c in Controls)
        if (c is MyControlType)
            ((MyControlType)c).DoSomething();
    Ca marche, mais le compilateur me lance un "performance warning". Car effectivement, il y a des casts dans tous les sens dans cette boucle. J'imagine par exemple que le is effectue un "cast cache".

    Comment faire, donc, pour faire cela proprement?

  2. #2
    Membre chevronné Avatar de Er3van
    Homme Profil pro
    Architecte Logiciel
    Inscrit en
    Avril 2008
    Messages
    1 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte Logiciel
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2008
    Messages : 1 430
    Points : 2 227
    Points
    2 227
    Par défaut
    Et comme ça ?

    Code c# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    foreach (MyControlType mc in Controls.Where(c => c is MyControlType)) {
         mc.DoSomething();
    }

  3. #3
    Membre éprouvé

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Juin 2011
    Messages
    487
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2011
    Messages : 487
    Points : 945
    Points
    945
    Par défaut
    Bonjour,

    tu peux créer une méthode virtuelle DoSomething() dans ta classe mère que tu override dans ta classe fille avec les opérations à faire. Tu ne mets rien dans la méthode de la classe mère et ensuite tu boucles juste en appelant la méthode. Si c'est une mère, la méthode est vide, si c'est une fille, la méthode contient les opérations à faire.

  4. #4
    Membre chevronné Avatar de Er3van
    Homme Profil pro
    Architecte Logiciel
    Inscrit en
    Avril 2008
    Messages
    1 430
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Architecte Logiciel
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2008
    Messages : 1 430
    Points : 2 227
    Points
    2 227
    Par défaut
    Citation Envoyé par MaximePalmisano Voir le message
    tu peux créer une méthode virtuelle DoSomething() dans ta classe mère que tu override dans ta classe fille avec les opérations à faire. Tu ne mets rien dans la méthode de la classe mère et ensuite tu boucles juste en appelant la méthode. Si c'est une mère, la méthode est vide, si c'est une fille, la méthode contient les opérations à faire.
    Si tu peux éditer la classe mère c'est sans doute le plus simple en effet pour éviter les cast.

  5. #5
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    Merci pour vos reponses.
    Malheureusement non, je ne peux pas editer la classe mere, qui est une classe du framework. Je ne peux meme pas modifier la collection, qui appartient a la classe Windows.Form.

    Je pense donc que la solution va etre celle de Er3van.


  6. #6
    Membre chevronné
    Avatar de Sehnsucht
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Octobre 2008
    Messages
    847
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Lot et Garonne (Aquitaine)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Octobre 2008
    Messages : 847
    Points : 2 209
    Points
    2 209
    Par défaut
    Bonjour,

    Tout en restant en Linq et basé sur la solution d'Er3van il faut savoir qu'il existe déjà exactement ce qui est demandé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    foreach (MyControlType mc in Controls.OfType<MyControlType>()) {
         mc.DoSomething();
    }
    Cordialement !

  7. #7
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    269
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 269
    Points : 460
    Points
    460
    Par défaut
    Bonjour,

    Sauf erreur de ma part, l'IL généré par le compilateur à partir du code d'Er3van
    sera du même acabit que celui issu de ton premier code.

    En effet il y a un cast caché dans le foreach, on fait dans tout les cas le test avec "is".
    Pour moi ça reviens strictement a la même chose, sauf que dans un cas le compilateur est capable de t'indiquer qu'il y a un potentiel problème de performance, et pas dans l'autre.

  8. #8
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 125
    Points
    25 125
    Par défaut
    moi je ne vois rien qui mène à se poser des questions de performance là dessus

  9. #9
    r0d
    r0d est déconnecté
    Expert éminent

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 265
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 265
    Points : 6 686
    Points
    6 686
    Billets dans le blog
    2
    Par défaut
    Oui aparamment c'est juste que dans un cas il parvient a trouver qu'il y a un probleme, et dans l'autre non.
    Je pensais qu'on aurait pu eviter ces casts caches, sans toutefois avoir la moindre idee de comment faire concretement. Mais theoriquement, il me semble qu'en c# les types ont un id, donc je pensais a une solution se basant sur cet id, plutot que de tenter le cast.

  10. #10
    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 Pol63 Voir le message
    moi je ne vois rien qui mène à se poser des questions de performance là dessus
    Absolument. Si y'a des problèmes de perf pour ça, c'est qu'il ya des milliers (des millions ?) de contrôles, et s'il y a des milliers de contrôles, c'est qu'il y a un souci de conception...

    Mais pour une problématique plus générale, j'appuie la suggestion de Sehnsucht. Linq propose une jolie méthode OfType, qui fait ce qu'on lui demande, de façon efficace.

  11. #11
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par r0d Voir le message
    Ca marche, mais le compilateur me lance un "performance warning".
    Ca m'étonnerait que ce soit le compilateur... tu n'utiliserais pas un outil comme Resharper ou autre ?

    Sinon, tu peux utiliser l'opérateur as qui est parfaitement adapté à ce genre de chose :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    foreach (Control c in Controls)
    {
        MyControlType x = c as MyControlType;
        if (x != null)
            x.DoSomething();
    }
    Sinon, si tu es en 3.5 ou supérieur, la meilleure solution est celle de Sehnsucht avec la méthode OfType

  12. #12
    Expert éminent sénior Avatar de Pol63
    Homme Profil pro
    .NET / SQL SERVER
    Inscrit en
    Avril 2007
    Messages
    14 177
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 177
    Points : 25 125
    Points
    25 125
    Par défaut
    à tous les coups le oftype parcourt la collection, vérifie le type, et cast pour remplir un list<T> ou autre
    linq apporte un gain de lisibilité mais dans ce cas pas beaucoup plus je pense

  13. #13
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par Pol63 Voir le message
    à tous les coups le oftype parcourt la collection, vérifie le type, et cast pour remplir un list<T> ou autre
    linq apporte un gain de lisibilité mais dans ce cas pas beaucoup plus je pense
    A priori l'implémentation de OfType doit être de cet accabit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source)
    {
        foreach(object o in source)
        {
            if (o is TResult)
                yield return (TResult)o;
        }
    }
    Donc effectivement ça pose le même problème de performance que le code d'origine. Mais bon, je pense que pour la plupart des cas la différence de perf n'aura pas beaucoup d'impact, et le gain de lisibilité est appréciable

    En tous cas ce qui est sûr c'est que ça ne remplit pas une liste avant de la renvoyer ; ça renvoie les résultats au fur et à mesure qu'ils sont lus

  14. #14
    Membre confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mars 2011
    Messages
    269
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2011
    Messages : 269
    Points : 460
    Points
    460
    Par défaut
    Bon je viens de verifier avec un ILSpy

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    foreach (MyControlType mc in Controls.Where(c => c is MyControlType)) 
    {
         mc.DoSomething();
    }
    produit bien un cast.
    Ca n'apporte donc rien par rapport au code de base.

    Comme le dit tomlev, l'implementation de OfType (toujours d'apres ILSpy) est la 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
    public static IEnumerable<TResult> OfType<TResult>(this IEnumerable source)
    {
    	if (source == null)
    	{
    		throw Error.ArgumentNull("source");
    	}
    	return Enumerable.OfTypeIterator<TResult>(source);
    }
     
    private static IEnumerable<TResult> OfTypeIterator<TResult>(IEnumerable source)
    {
    	foreach (object current in source)
    	{
    		if (current is TResult)
    		{
    			yield return (TResult)current;
    		}
    	}
    	yield break;
    }
    Quand à l'utilisation de "as"
    Et bien "as" utilise "is", la difference se fait au niveau du cast il n'y en a pas, c'est un retour conditionnel.


    Pour ce qui est du warning evoqué dans le sujet de base.
    Ce n'est pas resharper qui le génére, mais l'analyse de code fournit avec Visual: warning CA1800.
    Ce warning indique au developpeur qu'il peut éliminer son cast, notament avec "as".
    L'analyse de code oublie completement de traiter le cas de Linq.


    conclusion pour un parcours simple comme celui-ci, "as" c'est bien.

  15. #15
    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 antoine.debyser Voir le message
    Ce warning indique au developpeur qu'il peut éliminer son cast, notament avec "as".
    Et tant qu'à en#@er les mouches: OfType ne peut pas utiliser 'as', car 'as' ne fonctionne qu'avec les types référence, et que le paramètre générique de OfType n'a pas de contrainte le forçant à être un type référence.(par exemple, int i = obj as int n'aurait pas de sens ; que renvoyer si ce n'est pas un int ? Par contre, le compilo gère les nullable, qui sont techniquement des structs, mais pour lesquels l'opérateur 'as' est dispo.)

    On aurait donc le meilleur des deux mondes avec ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public static class MexExtensionsDeLaMort
    {
       public static IEnumerable<T> OfTypeRef<T>(this IEnumerable source) where T : class
       {
         foreach(object obj in source)
         {
            T casté = obj as T; // on peut car T est un type référence
            if (casté != null)
              yield return casté;
         }
       }
    }
    Mais bon, y'a trèèèèès souvent mieux à faire que s'interroger sur les perfs des casts sur une GUI, dont les méthodes qui accèdent aux contrôles ne sont pas appelées ni assez souvent, ni avec assez de volumes pour que ça vaille la peine.

  16. #16
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    Et un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    foreach (Control c in Controls)
        if (c.GetType().Equals(typeof(MyControlType)))
            ((MyControlType)c).DoSomething();

  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
    Citation Envoyé par brachior Voir le message
    Et un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    foreach (Control c in Controls)
        if (c.GetType().Equals(typeof(MyControlType)))
            ((MyControlType)c).DoSomething();
    Marche pas : tu refuses ici les objets d'un type dérivé de MyControlType. Et je doute fort que GetType() suivi d'un cast soit plus rapide que 'as'.

  18. #18
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    Citation Envoyé par Guulh
    Tu refuses ici les objets d'un type dérivé de MyControlType.
    Citation Envoyé par r0d
    Et je voudrais effectuer un traitement sur chaque element de cette collection mais seulement sur les objets de type Fille.
    Faudrait savoir ^^

    C'est sur qu'un Equals doit être plus couteux ...
    Mais ça retire le double cast

    Soit dit en passant ...
    Je sais très bien que c'est super laid ce que j'ai écrit ^^

  19. #19
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 753
    Points
    39 753
    Par défaut
    Citation Envoyé par brachior Voir le message
    Faudrait savoir ^^
    Bah les objets dérivés de Fille sont aussi des Fille...

  20. #20
    Membre actif Avatar de brachior
    Homme Profil pro
    Doctorant
    Inscrit en
    Mai 2011
    Messages
    190
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Doctorant
    Secteur : Enseignement

    Informations forums :
    Inscription : Mai 2011
    Messages : 190
    Points : 293
    Points
    293
    Par défaut
    Rah ça chipote là ^^

Discussions similaires

  1. Utilisartion d'une arraylist dans une boucle, question de performance
    Par Djobird dans le forum Collection et Stream
    Réponses: 4
    Dernier message: 20/07/2007, 17h28
  2. performance des 'cast'
    Par me_myself dans le forum C++
    Réponses: 27
    Dernier message: 06/12/2006, 15h49
  3. Réponses: 2
    Dernier message: 28/08/2006, 13h16
  4. Problème de Boucle (Perform: Ouille!)
    Par ted the Ors dans le forum Cobol
    Réponses: 13
    Dernier message: 23/07/2006, 21h00
  5. [Performance] LEFT JOIN vs SELECT dans une boucle (PHP)
    Par frochard dans le forum Requêtes
    Réponses: 4
    Dernier message: 28/10/2005, 17h45

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