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 :

Polymorhpisme Héritage et liste


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur
    Avatar de toopac
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Ille et Vilaine (Bretagne)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 940
    Par défaut Polymorhpisme Héritage et liste
    Bonjour,

    J'ai eu un soucis récemment avec le polymorphisme dans une liste.

    Je vais poser le problème avant, ça sera peut être plus clair :

    J'ai une classe abstraite A, et deux classes (B et C) qui en héritent :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public abstract class A { public string Value { get; set; } }
    public class B : A { public B(string value) { Value = value; } }
    public class C : A { public C(string value) { Value = value; } }
    Je veux faire un traitement quelconque sur une liste de ces objets (B et C).
    Pour l'exemple disons que ce traitement c'est le remplacement d'un élément dans une liste par un autre.

    Voilà le code :
    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
    class Program
    {
        static void Main(string[] args)
        {
            List<B> listB = new List<B> { new B("B1"), new B("B2"), new B("B3") };
            List<C> listC = new List<C> { new C("C1"), new C("C2"), new C("C3") };
     
            B b = new B("B22");
            C c = new C("C22");
     
            replace(listB[1], b, listB); // les valeurs de la liste deviennent "B1", "B22", "B3"
            replace(listC[1], c, listC); // les valeurs de la liste deviennent "C1", "C22", "C3"
        }
        // [...]
    }
    Afin de factoriser le code, je ne veux créer qu'une seule méthode replace qui fasse ce traitement pour les deux classes.

    Pour coder cette fameuse méthode, je voulais faire ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public static void replace(A oldA, A newA, List<A> listAs)
    {
        listAs.Insert(listAs.IndexOf(oldA), newA);
        listAs.Remove(oldA);
    }
    Seulement avec ce code j'obtiens l'erreur de compilation suivante :
    cannot convert from 'System.Collections.Generic.List<Appli.B>' to 'System.Collections.Generic.List<Appli.A>'
    Si j'ai bien compris, cela vient du fait que List<T> n'est pas covariant (alors que IEnumerable<T> l'est...).
    Cela dit, je comprends pas très bien pourquoi, surtout que j'ai réussi à m'en sortir autrement en utilisant les génériques :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    public static void foo<T>(T oldA, T newA, List<T> listAs)
      where T : A
    {
        listAs.Insert(listAs.IndexOf(oldA), newA);
        listAs.Remove(oldA);
    }
    J'ai donc réussi à faire ce que je voulais faire, mais sans trop comprendre pourquoi. Pour moi les deux codes sont identiques...

    Si quelqu'un pouvais m'éclairer.

    Merci d'avance.

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

    Informations professionnelles :
    Activité : Développeur .NET

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

    Je vais me risquer à une réponse

    D'une part l'absence de co/contravariance dans List<T> (ou IList<T>) vient du fait qu'ils possèdent un indexeur avec get et set donc l'argument T devrait être à la fois in et out.

    D'autre part, dans le code généré/utilisé durant l'exécution, la version générique n'existe pas en tant que telle, lorsque le JIT rencontre une instanciation/utilisation d'un (nouveau) type générique, il génère le code adéquat ainsi durant l'exécution seront générées (grosso modo) les méthodes suivantes:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public static void foo(B oldA, B newA, List<B> listAs)
    {
        listAs.Insert(listAs.IndexOf(oldA), newA);
        listAs.Remove(oldA);
    }
     
    public static void foo(C oldA, C newA, List<C> listAs)
    {
        listAs.Insert(listAs.IndexOf(oldA), newA);
        listAs.Remove(oldA);
    }
    Et là on voit bien que cela ne pose plus de problème, la "duplication de code" étant gérée à l'exécution. Ta seconde serait "équivalente" à ta première si tu l'utilisais comme ceci (et tu retrouverais la même erreur):
    Replace<A>(listB[1], b, listB);

    Quelqu'un connaissant mieux que moi les rouages internes, apportera sans doute plus de précisions

    Cordialement !

  3. #3
    Modérateur
    Avatar de toopac
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Ille et Vilaine (Bretagne)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 940
    Par défaut
    Bonjour,

    Donc si j'ai bien compris, avec la méthode utilisant les génériques, c'est le compilateur JIT qui fait le boulot à ma place.

    Je réponds un peu tard, j'ai laissé le sujet ouvert une semaine au cas où quelqu'un aurait d'autres choses à ajouter.

    Du coup je passe le tout en

    Merci encore

  4. #4
    Membre Expert

    Homme Profil pro
    Développeur .NET
    Inscrit en
    Novembre 2010
    Messages
    2 067
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Novembre 2010
    Messages : 2 067
    Par défaut
    tu peux même crée une méthode d'extension
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        public static class Extension
        {
            public static void Replace<T>(this List<T> listAs, T oldA, T newA)
            {
                listAs.Insert(listAs.IndexOf(oldA), newA);
                listAs.Remove(oldA);
            }
        }
    Tu peux spécifier que T hérite de A si tu veux.
    Ainsi tu peux l'appeler comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     listB.Replace(listB[1], b);

  5. #5
    Modérateur
    Avatar de toopac
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2009
    Messages
    940
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Ille et Vilaine (Bretagne)

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 940
    Par défaut
    Ok merci, en réalité mon code est plus complexe. Le "replace" était un exemple pour illustrer mon problème.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Héritage et liste
    Par Flaburgan dans le forum C#
    Réponses: 12
    Dernier message: 06/04/2011, 14h22
  2. Héritage et List
    Par Benoit_T dans le forum Langage
    Réponses: 3
    Dernier message: 11/08/2010, 12h42
  3. Héritage et liste variable d'arguments
    Par jimaitou dans le forum Débuter
    Réponses: 9
    Dernier message: 08/03/2009, 20h52
  4. empecher héritage dans liste à puce imbriquées
    Par zamanika dans le forum Mise en page CSS
    Réponses: 2
    Dernier message: 15/03/2007, 16h18
  5. Héritage et listes chainées...
    Par syntaxerror dans le forum C++
    Réponses: 7
    Dernier message: 04/05/2005, 21h18

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