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 :

Polymorphisme et templates


Sujet :

C#

  1. #1
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut Polymorphisme et templates
    Bonjour,

    J'ai un petit soucis avec les templates et le polymorphisme :
    J'ai une classe Mère abstraite et des classes FilleA et FilleB qui en héritent.
    Ma classe Mère va avoir des méthodes que vont devoir surcharger les classe filles.
    Seulement, elle vont devoir changer les types des paramètres.
    J'ai donc fait comme ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    abstract class Mère<T>
    {
        public abstract T maMéthode(T param)
    }
    class Fille1 : Mère<T1>
    {
        public T1 maMéthode(T1 param)
    }
    class Fille2 : Mère<T2>
    {
        public T2 maMéthode(T2 param)
    }
    Jusqu'ici tout va bien !
    Mais, dans une autre classe j'ai besoin de créer soit une instance de Fille1 soit de fille 2 donc j'ai fait ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public static Mère()
    {
        if test
            return new Fille1;
        else
            return new Fille2;
    }
    Mais là il me dit
    L'utilisation du type 'Mère<T>' générique requiert les arguments de type '1'

  2. #2
    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
    Par défaut
    Alors déjà ce ne sont pas des templates, mais des génériques... ça ressemble, mais en fait il y a pas mal de différences entre les templates de C++ et les génériques de C#.

    D'autre part, c'est quoi ce code ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public static Mère()
    {
        if test
            return new Fille1;
        else
            return new Fille2;
    }
    La syntaxe ressemble à celle d'un constructeur statique, sauf qu'on peut pas rendre public un constructeur statique... Je pense qu'il manque un bout du code (au pif, le nom de la méthode)

    Enfin en tous cas, le problème est qu'il n'y a pas de classe Mère non générique. Si tu utilises Mère, tu dois spécifier le paramètre de type générique. Il n'existe pas de classe de base commune entre Fille1 et Fille2, car elles n'utilisent pas le même type pour le T de Mère<T>.

    Si tu as besoin d'une classe de base commune, tu peux toujours déclarer une classe Mère non générique, et faire hériter Mère<T> de Mère.

  3. #3
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Alors déjà ce ne sont pas des templates, mais des génériques... ça ressemble, mais en fait il y a pas mal de différences entre les templates de C++ et les génériques de C#.
    Au temps pour moi tu as raison

    Pardon, il manquait en effet le nom de ma méthode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    public static Mère getInstance()
    {
        if test
            return new Fille1;
        else
            return new Fille2;
    }
    En fait j'essaye d'implémenter une fabrique (factory) qui instancierait l'une ou l'autre des classes filles mais peut-être que je m'y prends mal ?
    Comment on fait dans le cas ou les méthodes des classes filles n'ont pas la même signature que celles de la classe mère, mais qu'il s'agit tout de même d'un "héritage" ? Normalement, comme ma classe mère est abstraite, je suis sensé redéfinir exactement les mêmes méthodes dans les filles mais le fait est que les types de retour ne sont pas les mêmes.

  4. #4
    Membre émérite Avatar de kheironn
    Homme Profil pro
    Chef de projets technique C# / MVC / .Net
    Inscrit en
    Février 2007
    Messages
    822
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations professionnelles :
    Activité : Chef de projets technique C# / MVC / .Net
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2007
    Messages : 822
    Par défaut
    Ah toujours la grossière erreur sémentique liée à l'abus de langage !
    Fille ne peut pas hériter de Mère puisque Mère est une spécialisation de Fille ; la preuve : une mère est une fille qui a des enfants (avec des méthodes du genre allaiter(), accoucher(), changerCouche() etc. dont fille ne dispose pas puisqu'elle n'est pas mère). + Personnellement, je préfère parler de classe généralisée et de classe spécialisée.

    Citation Envoyé par Gaetch Voir le message
    En fait j'essaye d'implémenter une fabrique (factory) qui instancierait l'une ou l'autre des classes filles mais peut-être que je m'y prends mal ?
    Ah bon ? j'ai pas trop l'impression qu'elle ressemble à ça ta factory.

    Pour le polymorphisme, la surcharge (override) n'admet pas de changement de prototype. Par contre, avec new, tu peux créer une nouvelle méthode. Tu devrais jeter un coup d'oeil sur msdn pour savoir axactement ce que font ces mots-clefs.

  5. #5
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    Citation Envoyé par kheironn Voir le message
    Ah toujours la grossière erreur sémentique liée à l'abus de langage !
    Fille ne peut pas hériter de Mère puisque Mère est une spécialisation de Fille ; la preuve : une mère est une fille qui a des enfants (avec des méthodes du genre allaiter(), accoucher(), changerCouche() etc. dont fille ne dispose pas puisqu'elle n'est pas mère). + Personnellement, je préfère parler de classe généralisée et de classe spécialisée.
    Arrêteuh tu m'embrouilles !
    Citation Envoyé par kheironn Voir le message
    Ah bon ? j'ai pas trop l'impression qu'elle ressemble à ça ta factory.
    Pour être plus précis je veux qu'elle ressemble à quelque chose comme l'image en pièce jointe.

    Grosso-modo hein, dans l'idée ! Mes classes métier ne sont pas les mêmes.

    Citation Envoyé par kheironn Voir le message
    Pour le polymorphisme, la surcharge (override) n'admet pas de changement de prototype. Par contre, avec new, tu peux créer une nouvelle méthode. Tu devrais jeter un coup d'oeil sur msdn pour savoir axactement ce que font ces mots-clefs.
    J'ai saisi mais je veux pouvoir appeler MaClasseGenerique.maMethode, qui appellera maMethode d'une des classes spécialisées automatiquement.
    Images attachées Images attachées  

  6. #6
    Membre chevronné
    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
    Par défaut
    L'erreur viens de la déclaration des filles
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Fille1 : Mère<T1>
    Mais où est définit la classe "T1", si la classe T1 n'est pas définit la bonne définition est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Fille1<T1> : Mère<T1>
    Quand a l'erreur que pointais tomlev
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public static Mère getInstance()
    {
        if test
            return new Fille1();//new Fille1;
        else //ou un truc du genre
            return Fille2.Create();//new Fille2;
    }

  7. #7
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    Citation Envoyé par antoine.debyser Voir le message
    L'erreur viens de la déclaration des filles
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Fille1 : Mère<T1>
    Mais où est définit la classe "T1", si la classe T1 n'est pas définit la bonne définition est
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    class Fille1<T1> : Mère<T1>
    Non, d'après le site de Microsoft :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    When deriving from a generic base class, you must provide a type argument instead of the base-class's generic type parameter:
     
    public class BaseClass<T>
    {...}
    public class SubClass : BaseClass<int>
    {...}

  8. #8
    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
    Par défaut
    Citation Envoyé par Gaetch Voir le message
    Non, d'après le site de Microsoft :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    When deriving from a generic base class, you must provide a type argument instead of the base-class's generic type parameter:
     
    public class BaseClass<T>
    {...}
    public class SubClass : BaseClass<int>
    {...}
    Bah ça dépend de ce que tu veux faire... si tu fais comme ça, tu crées une classe qui n'est plus générique. Elle hérite de BaseClass<int>, pas de BaseClass<T>.

  9. #9
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    Citation Envoyé par tomlev Voir le message
    Bah ça dépend de ce que tu veux faire... si tu fais comme ça, tu crées une classe qui n'est plus générique. Elle hérite de BaseClass<int>, pas de BaseClass<T>.
    Heu bin non, l'intérêt des génériques est là nan ?
    Mettre un type 'générique' dans la classe de base, et le remplacer dans les classes héritées ! Si le type T est le même dans les deux, on a pas besoin d'utiliser les génériques à ce que je sache !

  10. #10
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    --

    Je pense que j'ai un souci dans mon analyse, car s'il est vrai que le type de retour T de maMéthode est différent dans chaque classe fille (T1, T2, etc.), je pense que T1 et T2 doivent hériter de T sinon il y a erreur au niveau du design. Je dois donc trouver le type T qui sera une généralisation de T1, T2 et etc. et utiliser ce type explicitement dans Mère et je n'aurai pas besoin d'utiliser les génériques.

  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
    Par défaut
    Citation Envoyé par Gaetch Voir le message
    Heu bin non, l'intérêt des génériques est là nan ?
    Mettre un type 'générique' dans la classe de base, et le remplacer dans les classes héritées !
    Pas nécessairement... on utilise tout le temps des types génériques sans en hériter, par exemple List<T> ou Nullable<T>

    Citation Envoyé par Gaetch Voir le message
    Si le type T est le même dans les deux, on a pas besoin d'utiliser les génériques à ce que je sache !
    Bah je vois pas le rapport... tu peux très bien faire une classe générique qui hérite d'une autre classe générique, si tu veux la spécialiser en restant générique. Par exemple ObservableCollection<T> hérite de Collection<T> en lui ajoutant des capacités de notification, et on peut toujours créer une ObservableCollection<string> ou une ObservableCollection<int>

    Mais tout ça n'a pas vraiment de rapport avec ton problème, vu qu'apparemment dans ton cas tu as besoin de fixer le type du paramètre générique dans les classes dérivées. Comme je disais plus haut, le problème quand tu fais ça est que tes classes filles n'héritent plus de la même classe : l'une hérite de Mère<T1> et l'autre de Mère<T2> (*). Il n'y a donc plus de classe de base commune entre les deux classes Fille (à part Object), et donc tu ne peux pas faire une méthode qui renvoie l'une de ces 2 classes. La seule chose que tu peux faire, c'est créer une classe non générique Mère et en faire hériter Mère<T>. Dans ce cas Fille1 et Fille2 auront au moins cet ancêtre en commun. Et ta méthode GetInstance pourra renvoyer le type Mère (non générique)


    (*) au fait, d'où ils sortent ces types T1 et T2 ? Je suppose qu'en réalité tu utilises de vrais types à la place ?

  12. #12
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    Oui T c'est un générique mais T1 et T2 sont des Classes concrètes.
    Dans mon cas j'ai besoin de spécifier le type dans les classes filles.
    Mais comme dit, il y a un problème de design dans mon code. T1 et T2 doivent hériter de T qui lui ne dois plus être un générique mais une Classe qui existe bien. Je dois pouvoir m'en sortir sans les génériques et ça sera plus correct.

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

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Gaetch Voir le message
    Oui T c'est un générique mais T1 et T2 sont des Classes concrètes.
    Dans mon cas j'ai besoin de spécifier le type dans les classes filles.
    Mais comme dit, il y a un problème de design dans mon code. T1 et T2 doivent hériter de T qui lui ne dois plus être un générique mais une Classe qui existe bien. Je dois pouvoir m'en sortir sans les génériques et ça sera plus correct.
    Donc déjà tu peux contraindre le paramètre de généricité de ta classe Mere<T> avec la clause "where".

    Si on appelle TBase la classe de base du paramétre de généricité, tu peux donc manipuler dans Mere<T> le paramètre de généricité comme étant un TBase (puisque tu l'as contraint).

    Sinon, pour les génériques, une règle de design simple à observer :

    - quand tu crée une classe Mere<T> qui à priori n'hérite de rien, regroupe tous les membres (variables, propriétés,méthodes, event, etc ..) non génériques dans une classe Mere abstraite dont tu fais hériter Mere<T>; ça simplifie beacoup la vie.

    Exemple, pour illustrer mon propos; admettons que ta classe ressemble à cela :

    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
    	public class Mere<T> where T : TBase, new()
    	{
    		T _genericMember;
    		int _anotherMember;
    		public T GenericValue
    		{
    			get;
    			set;
    		}
    		public int NonGenericValue
    		{
    			get;
    			set;
    		}
    		public int NonGenericMethod()
    		{
    			return 42;
    		}
    		public T GenericMethod()
    		{
    			return new T();
    		}
    	}
    Tu as tout interêt à remplacer cette implémentation par celle ci :

    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
    	public abstract class Mere
    	{
    		protected _anotherMember;
    		public int NonGenericValue
    		{
    			get;
    			set;
    		}
    		public virtual int NonGenericMethod()
    		{
    			return 42;
    		}
    	}
    	public class Mere<T> : Mere where T : TBase, new()
    	{
    		T _genericMember;
    		public T GenericValue
    		{
    			get;
    			set;
    		}
    		public T GenericMethod()
    		{
    			return new T();
    		}
    	}

  14. #14
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    Je vais vous donner le cas concret vous pourrez peut-être mieux voir ce que je veux faire !

    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
    abstract class BaseDeDonnees<C, R>
    {
        public abstract C ouvreConnexion();
        public abstract void fermeConnection(C connexion);
        public abstract void executeRequeteNonQuery(String requete);
        public abstract R executeRequeteReader(String requete);
        public abstract Object executeRequeteScalar(String requete);
    }
     
    class BaseDeDonneesMySql : BaseDeDonnees<MySqlConnection, MySqlDataReader>
    {
        public override MySqlConnection ouvreConnexion() { ... }
        public override void fermeConnection(MySqlConnection connexion) { ... }
        public override void executeRequeteNonQuery(String requete) { ... }
        public override MySqlDataReader executeRequeteReader(String requete) { ... }
        public override Object executeRequeteScalar(String requete) { ... }
    }
     
    class FabriqueBaseDeDonnees
    {
        public static BaseDeDonnees getBdd()
        {
            switch (Application.sgbd)
            {
                case Sgbd.MySQL:
                    return new BaseDeDonneesMySql();
                case ...
            }
        }
    }

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

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Gaetch Voir le message
    Je vais vous donner le cas concret vous pourrez peut-être mieux voir ce que je veux faire !
    A priori, ton cas concret ne sert à rien : il n'est d'aucune utilité de balader les types concret des classes d'accès à ADO.Net dans un programme; on dispose des interfaces, cela suffit.

    Tu n'as aucun bénéfice à l'usage de la généricité dans ton cas.

  16. #16
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    Citation Envoyé par Bluedeep Voir le message
    il n'est d'aucune utilité de balader les types concret des classes d'accès à ADO.Net dans un programme; on dispose des interfaces, cela suffit.
    J'ai pas compris, tu peux m'expliquer vite fait ?

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

    Informations professionnelles :
    Activité : Chef de projet NTIC

    Informations forums :
    Inscription : Janvier 2007
    Messages : 6 604
    Par défaut
    Citation Envoyé par Gaetch Voir le message
    J'ai pas compris, tu peux m'expliquer vite fait ?
    Retourner le MySqlDataReader en sortie de méthode executeRequeteReader ne sert rigoureusement à rien.

    Cette méthode n'a pas à être générique;

    Il suffit de la définir ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    IDataReader executeRequeteReader(String requete);

  18. #18
    Membre éclairé
    Inscrit en
    Juillet 2007
    Messages
    433
    Détails du profil
    Informations forums :
    Inscription : Juillet 2007
    Messages : 433
    Par défaut
    Je suis allé voir ce qu'était ADO.Net je ne connaissais pas, pour info mon exemple a une vocation didactique, c'est pourquoi je "réinvente la roue" et code des choses qui existent déjà, c'est pour apprendre un peu les design patterns et la manipulation de bases de données en CSharp. Mais néanmoins ça à l'air intéressant j'ai téléchargé un cours dans la section tutoriel je vais voir si je peux mettre en place ça !

Discussions similaires

  1. simuler le polymorphisme via les templates
    Par ronaldino dans le forum C++
    Réponses: 10
    Dernier message: 28/11/2006, 00h15
  2. Template et polymorphisme
    Par fabienpot dans le forum Langage
    Réponses: 9
    Dernier message: 07/09/2006, 16h32
  3. Réponses: 14
    Dernier message: 09/05/2006, 15h23
  4. Réponses: 8
    Dernier message: 28/03/2006, 15h53
  5. Template et polymorphisme
    Par Pierre_IPROS dans le forum Langage
    Réponses: 19
    Dernier message: 09/10/2005, 23h04

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