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 :

Problème de modélisation avec des classes génériques


Sujet :

C#

  1. #1
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

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

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut Problème de modélisation avec des classes génériques
    Bonjour,

    Suite à mon précédent sujet concernant la modélisation avec des classes génériques, j'ai tenté quelques techniques, mais sans succès.

    J'espère que quelqu'un pourra m'expliquer ce que j'ai loupé, ou pas compris dans les classes suivantes.

    La classe Feuille qui contient une liste de Colonne.
    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
     
    namespace test
    {
     
        public class Feuille
        {
            /// Liste des colonnes de la feuille
            private IList<IColonne> colonnes;
     
     
            public Feuille()
            {
                this.colonnes = new List<IColonne>();
            }
     
            public IList<IColonne> Colonnes
            {
                get
                {
                    return this.colonnes;
                }
                set
                {
                    this.colonnes = value;
                }
            }
        }
    }
    L'interface IColonne

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    namespace test
    {
        public interface IColonne
        {
            IList<ICellule> Cellules
            {
                get;
                set;
            }
        }
    }
    L'interface ICellule
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    namespace test
    {
        public interface ICellule
        {
            Object Valeur
            {
                get;
                set;
            }
        }
    }
    Ma classe de Colonne Générique
    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
     
    namespace test
    {
        public class Colonne<T> : IColonne
        {
            private IList<ICellule> list = new List<Cellule<T>>();
            //Sur cette donnée membre, Visual me dit qu'il ne peut pas convertir Cellule<T> en ICellule. Mais Cellule<T> implémente l'interface ICellule
     
            public IList<ICellule> Cellules
            {
                get
                {
                    return list;
                }
                set
                {
                    list = value;
                }
            }
        }
    }
    Je ne comprend pas pourquoi j'ai l'erreur de conversion impossible ici


    Et ma classe de Cellule générique

    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
     
    namespace test
    {
        public class Cellule<T> : ICellule
        {
            private T valeur;
     
            public Object Valeur //Ici j'aurais préféré mettre public T Valeur, mais la signature ne correspond pas à l'interface ICellule.
            {
                get
                {
                    return valeur;
                }
                set
                {
                    valeur = (T)value;
                }
            }
        }
    }
    Dans cette classe, j'aurais apprécié que la propriété Valeur ai le type T et non pas Object. Mais T ne correspond pas à la signature de ICellule.Valeur. La aussi comment feriez-vous?

    C'est le code le plus propre que j'aimerai implémenter mais cela ne compile pas, et ce malgré l'utilisation d'interfaces non génériques.

    La contrainte principale est que une Colonne<T> ne puisse contenir qu'une IList<Cellule<T>>

    Comment solutionneriez-vous ceci? parce que la je tourne en rond sans trouver LA solution.

    Un énorme MERCI, à celui, ceux, qui m'aideront à résoudre ce problème.

  2. #2
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Malheureusement tu te heurtes a un problème de co-variance et de contra-variance qui fait que ce que tu souhaites faire est impossible car IList<T> n'est ni co-variant ni contra-variant.
    Explications :
    IList<T> définit (entre autres) la méthode Add qui permet d'ajouter un élément.

    Si maintenant on a la classe de base Vehicule et deux classes qui en héritent (Voiture et Camion).
    On peut faire ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    IList<Voiture> voitures = new List<Voiture>();
    Voiture voiture = new Voiture();
    voitures.Add(voiture);
    Mais on peut aussi faire ca :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Vehicule ve = new Camion();
    Maintenant, imagine qu'on dise que IList<Voiture> soit une IList<Vehicule>:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    IList<Vehicule> voitures = new List<Voiture>(); //Admettons que cela soit valide
    Vehicule camion = new Camion();
    voitures.Add(camion); // puisque c'est un IList<Vehicule> on a Add(Vehicule)
    On vient de tout casser: on a rangé une instance de Camion dans une List<Voiture>

    Cela ne peut pas marcher avec IList<T> car il faudrait que IList<T> soit co-variant (car T est utilisé par des méthodes comme type de sortie) et contra-variant sur T (car T est utilisé par des méthodes comme type d'entrée).

    Pour plus d'info: http://guruumeditation.developpez.co...tnet/variance/

  3. #3
    Membre habitué Avatar de touftouf57
    Profil pro
    Développeur .NET
    Inscrit en
    Décembre 2007
    Messages
    362
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Moselle (Lorraine)

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

    Informations forums :
    Inscription : Décembre 2007
    Messages : 362
    Points : 174
    Points
    174
    Par défaut
    Merci Nathanael,

    Lorsque tu as fait mention de covariance, un lointain souvenir m'est revenu comme un boomerang.

    Alors dans ce cas, comment contournerais-tu le problème?
    Abandon de la généricité et faire des classes "en dur". ColoneString, ColonneInt, ColonneFloat qui héritent de Colonne. Faire la même chose pour mes Cellules.
    Ou un autre type de Collection?
    Ou autre chose, mais la je ne vois pas quoi?

    Re-merci

  4. #4
    Rédacteur
    Avatar de Nathanael Marchand
    Homme Profil pro
    Expert .Net So@t
    Inscrit en
    Octobre 2008
    Messages
    3 615
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Expert .Net So@t
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2008
    Messages : 3 615
    Points : 8 080
    Points
    8 080
    Par défaut
    Tout dépend des besoins après
    Tu peux par exemple utiliser IEnumerable<out T> qui est covariant (comme l'indique le out).

  5. #5
    Membre averti
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2008
    Messages
    231
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2008
    Messages : 231
    Points : 359
    Points
    359
    Par défaut
    Que veux tu faire avec ta valeur ? Tu as besoin qu'elle soit typée ? tu veux/peux lui faire faire un traitement ?

    Exemple, es ce qu'il serait possible que dans ton application tu puisses définir une interface IValeur qui implémente une méthode Execute() qui exécute un traitement ou qui prend un paramètre particulier.

    Ensuite tu implémentes toutes tes Valeurs possible (String, Int, Toto, Tata, etc.) et quand à besoin de faire le traitement, qui sera forcément particulier à chaque valeur, alors tu appelles la méthodes dites.

Discussions similaires

  1. problème avec une classe générique
    Par bard123 dans le forum Langage
    Réponses: 4
    Dernier message: 27/06/2008, 11h09
  2. Problème de multimap avec des classes dérivées
    Par Bob94 dans le forum SL & STL
    Réponses: 3
    Dernier message: 06/05/2008, 02h02
  3. Problème avec une classe générique
    Par Core8 dans le forum C++
    Réponses: 3
    Dernier message: 19/03/2007, 03h18
  4. Problème avec des Class en asp
    Par titou250 dans le forum ASP
    Réponses: 3
    Dernier message: 06/06/2006, 13h22
  5. Réponses: 9
    Dernier message: 25/09/2005, 16h33

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