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 :

Héritage : changer le type de retour d'une implémentation de fonction


Sujet :

C#

  1. #1
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 413
    Points : 286
    Points
    286
    Par défaut Héritage : changer le type de retour d'une implémentation de fonction
    Bonjour à tous,

    Je voulais forcer les classes qui héritent d'une classe que j'ai créée à implémenter une fonction. J'ai donc créé une fonction abstraite dans ma classe de base.
    Le problème c'est que je ne sais pas exactement de quel type sera le type de retour de cette fonction.
    J'avais donc mis object comme type de retour mais, lors de l'implémentation, je suis donc également obligé de retourner le type object.

    Comment contourner cette limitation ou quel design dois-je utiliser pour arriver à ce résultat?

    Merci d'avance,
    Nicolas

  2. #2
    Expert éminent sénior
    Avatar de Skyounet
    Homme Profil pro
    Software Engineer
    Inscrit en
    Mars 2005
    Messages
    6 380
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Software Engineer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2005
    Messages : 6 380
    Points : 13 380
    Points
    13 380
    Par défaut
    Citation Envoyé par NicolasJolet Voir le message
    Bonjour à tous,

    Je voulais forcer les classes qui héritent d'une classe que j'ai créée à implémenter une fonction. J'ai donc créé une fonction abstraite dans ma classe de base.
    Le problème c'est que je ne sais pas exactement de quel type sera le type de retour de cette fonction.
    J'avais donc mis object comme type de retour mais, lors de l'implémentation, je suis donc également obligé de retourner le type object.

    Comment contourner cette limitation ou quel design dois-je utiliser pour arriver à ce résultat?

    Merci d'avance,
    Nicolas
    Une méthode générique ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public abstract T MyMethod<T>();
    Introduction à Silverlight 4 (new) ; Localisation d'une application Silverlight (new) ;
    Mon espace perso[/B]

    La connaissance s’acquiert par l’expérience, tout le reste n’est que de l’information. Albert Einstein[/SIZE]

  3. #3
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Pour construire une méthode qui renvois un type générique, qui n'est spécifié que par la classe fille, il n'y a que les methodes génériques de correct.

    En ADA, un langage non objet (avant ADA95) des années 8 0 c'était déjà possible
    Langage typée fort, avec déjà la généricité, c'est assez puissant, mais aujourd'hui le langage n'a plus aucun intérêt.
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  4. #4
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 413
    Points : 286
    Points
    286
    Par défaut
    Les méthodes génériques sont en effet une solution mais pas des plus élégantes à mon sens. Ça ne me plait pas trop de devoir indiquer quel type je choisi à chaque fois que j'appelle ma fonction.
    J'aurais voulu faire quelque chose du genre : définir une fonction générique dans ma classe de base et indiquer le type que je souhaite utiliser dans ma classe héritante.

    EDIT : mais je n'ai peut-être pas compris exactement comment définir le type dans ma classe fille?!

  5. #5
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Tu peux faire une méthode générique qui prend un type T et renvois un type T (T pour Type façon d'indiquer que c'est gnérique).

    Puis une méthode qui prend un string et renvois un string. Cette méthode ce charge d'appeler la générique.

    De cette manière tu n'as plus besoin d'appeler le type, et en plus ta méthode peu s'amuser à faire des controleurs du au type choisie avant et apres appel de la générique.

    Cela pourrait être pratique lorsque ton type est une classe que tu as créé.
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  6. #6
    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 NicolasJolet Voir le message
    Les méthodes génériques sont en effet une solution mais pas des plus élégantes à mon sens. Ça ne me plait pas trop de devoir indiquer quel type je choisi à chaque fois que j'appelle ma fonction.
    Pas la peine, si tu fais comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    abstract class Mere<T>
    {
        // des trucs
        public abstract T F();
        // d'autres trucs
    }
     
    class Fille : Mere<int>
    {
       public int F() { ... }
    }
    Tu pourras appeler F directement sur ta classe fille. ca dépend de ton scénario, mais si tu veux que la fonction F de la classe fille renvoie systématiquement un objet d'un type donné, ça me parait pas mal.
    ಠ_ಠ

  7. #7
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 413
    Points : 286
    Points
    286
    Par défaut
    Si j'ai bien compris la solution que tu proposes, ça ne règle pas totalement mon problème.
    Sachant que je dois implémenter ma classe abstraite, c'est un peu de la redondance si je dois à chaque fois créer une fonction pour encapsuler l'utilisation de ma fonction générique...

    EDIT : ce message était pour ced600

  8. #8
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 413
    Points : 286
    Points
    286
    Par défaut
    Avec une classe générique ça fonctionne effectivement bien

    Je n'ai qu'un seul problème : dans mon application utilisant mes classes, je souhaitais utiliser un tableau du type de ma classe de base, qui contiendrait en fait des objets du type des classes dérivées:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    cBase[] tab;
    foreach(cBase c in tab)...
    Maintenant que j'ai déclaré une classe générique pour la classe de base, il me demande d'expliciter le type à utiliser pour chaque utilisation du nom de ma classe de base :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    cBase<type>[] tab;
    foreach(cBase<type> c in tab)...
    Un peu contraignant :\

    Comment puis-je faire?

    Merci pour tous vos conseils.

  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
    Generics et héritage ne font pas bon ménage. un Mere<int> et un Mere<string> n'ayant aucun lien de parenté, tu ne peux pas créer de conteneur typé (i.e; autre que ArrayList ou object[]) contenant les deux à la fois.

    C'est normal : si tu veux faire un Machin[], avec une fonction F définie dans Machin, il faut bien que le compilo sache statiquement quel est le type de retour de F.

    On en parlait récemment dans un autre thread, où j'expliquais pourquoi une List<int> n'est pas une List<object>.
    ಠ_ಠ

  10. #10
    Expert éminent
    Avatar de _skip
    Homme Profil pro
    Développeur d'applications
    Inscrit en
    Novembre 2005
    Messages
    2 898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur d'applications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 898
    Points : 7 752
    Points
    7 752
    Par défaut
    Et oui, malheureusement pas de covariance en c# ( HELAS !!!!!!)
    La meilleure chose à faire dans ce cas, c'est de faire implémenter a ta classe de base une interface, ça résoud déjà certains problèmes. Tu peux ensuite créer un vecteur d'interface qui contient tes objets génériques sans forcément connaître leur type exact.

  11. #11
    Expert confirmé
    Avatar de ced600
    Homme Profil pro
    Développeur .NET
    Inscrit en
    Août 2006
    Messages
    3 364
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France

    Informations professionnelles :
    Activité : Développeur .NET

    Informations forums :
    Inscription : Août 2006
    Messages : 3 364
    Points : 4 061
    Points
    4 061
    Par défaut
    Juste pour répondre à NicolasJolet, ce qu j'ai proposé n'est pas de la redondance.
    Cela s'apparente plus à un système en couche.
    Une méthode de base, ta méthode générique, pour faire une certaine opération quelque soit le type.
    Des méthodes de plus haut niveau qui utilise ta méthode générique de bas niveau.

    Maintenant je ne sais pas si mettre deux couches dans une même classe est quelque chose de bien. en général on réuni plusieurs classes de bas niveau en un même composant (Dll, service, ...) pour l'utiliser comme framework, et des classes de plsu haut niveau dans un ou plusieurs composants utilisant le framework et offrant des services de plus haut niveau.

    Mais bon une classe de bas niveau et des filles implémantant des fonctions de plus haut niveau c'est viable.

    Lorsque l'héritage n'est plus adapté les interfaces restent la meilleur solution.
    Pourquoi faire compliqué lorsque l'on peut faire encore plus compliqué.

  12. #12
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 413
    Points : 286
    Points
    286
    Par défaut
    Effectivement, utiliser une interface que la classe mère implémente me permet de créer un tableau d'objets "du même type".
    Et la classe mère étant générique et possédant une méthode abstraite, elle me permet de forcer les classes filles à implémenter une méthode dont le type de retour est défini par le type choisi lors de l'héritage.

    Mais il semble effectivement que ça ne soit pas très intéressant dans mon cas d'essayer d'avoir un tableau d'objet du même type (type de l'interface dans mon cas) puisque je ne peux pas faire appel à la méthode commune, sachant que si je la défini dans mon interface, je dois faire une interface générique et le problème se pose à nouveau.

    Je vais donc tout simplement faire un ArrayList pour stocker mes objets et ne pas utiliser d'interface.

    Merci à tous pour votre aide,
    Nicolas

  13. #13
    Expert éminent
    Avatar de _skip
    Homme Profil pro
    Développeur d'applications
    Inscrit en
    Novembre 2005
    Messages
    2 898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur d'applications
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 898
    Points : 7 752
    Points
    7 752
    Par défaut
    Tu peux utiliser une methode wrapper

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        public class ClassBase<T> : IClass where T : new()
        {
     
            public T MyGenericMethod()
            {
                return new T();
            }
     
            public object MyMethod()
            {
                return MyGenericMethod();
            }
     
        }

    et dans l'interface :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
        interface IClass
        {
            object MyMethod();
        }

    Ca permet d'avoir a la fois le polymorphisme et la possibilité de travailler avec des méthodes à fort typage.
    Ca peut bien dépanner parfois.

  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
    Citation Envoyé par NicolasJolet Voir le message
    Je vais donc tout simplement faire un ArrayList pour stocker mes objets et ne pas utiliser d'interface.
    Et ca ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    abstract class GrandMere
    {
    // des trucs
    }
     
    abstract class Mere<T> : GrandMere
    {
        public abstract F();
    }
     
    class Fille : Mere<int>
    {
       public int F() { /* du code*/ }
    }
    Et là, plutôt qu'une ArrayList (bouh, je déteste ce relicat du FX 1 ), t'aurais une jolie liste de grand-mères.
    ಠ_ಠ

  15. #15
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 413
    Points : 286
    Points
    286
    Par défaut
    Salut, merci de vous intéresser plus en profondeur à mon problème.

    Citation Envoyé par Guulh Voir le message
    Et ca ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    abstract class GrandMere
    {
    // des trucs
    }
     
    abstract class Mere<T> : GrandMere
    {
        public abstract F();
    }
     
    class Fille : Mere<int>
    {
       public int F() { /* du code*/ }
    }
    Et là, plutôt qu'une ArrayList (bouh, je déteste ce relicat du FX 1 ), t'aurais une jolie liste de grand-mères.
    Cette solution fonctionne effectivement, mais ça ne résout pas plus mon problème qu'une interface puisque, au final, je ne peux pas appeler ma méthode F() sans faire un casting vu qu'elle n'est pas définie dans la classe GrandMere...
    La solution à mon problème serait de pouvoir définir une fonction mais de ne pas indiquer le type de retour (même générique) dans la classe GrandMere et de garder la généricité dans la classe mère.

  16. #16
    Membre habitué Avatar de BigNic
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    195
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2004
    Messages : 195
    Points : 154
    Points
    154
    Par défaut
    Sans être indiscret c'est quoi le cas concret d'utilisation de tous ça ?
    Au risque de passer pour un pinailleur de 1ere classe, je ne comprend pas du tout comment tu peux avoir besoin de de génércité et d'héritage en même temps, a moins d'avoir un problème de conception important; comme par exemple mélange de choux et de carrote, utilisants des carrotes génétiquement modifiées avec des gènes de choux.

  17. #17
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 413
    Points : 286
    Points
    286
    Par défaut
    Il est fort probable qu'il existe en fait une autre façon de faire en revoyant ma logique par exemple...

    Je souhaite créer des classes qui permettraient de faire des recherches de plusieurs types d'objet sur un ordinateur, par exemple des fichiers, des dossiers, des clés registres, ....
    Je souhaites passer à ces classes une certaine chaine de recherche, par exemple "C:\*.*" et qu'avec une fonction commune à toutes ces classes, je puisse obtenir en retour des objets correspondant à ma recherche.
    Je souhaitais pouvoir rechercher dans toutes mes classes avec le même nom de fonction mais que les objets retournés soient différents (des fichiers, dossiers, clés registre, ...).

  18. #18
    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
    Ton scénario me fait penser à l'implémentation de l'interface ICloneable. Elle définit une fonction Clone, qui renvoie un object (cette interface est plus vieille que le FX 2.0, donc pas de generics), hors on s'attend logiquement à ce que le clone d'un objet ait le même type.

    J'ai beaucoup vu ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    class Machin : ICloneable
    {
        public object ICloneable.Clone() // implémentation explicite
        {
           return this.Clone(); // appele la fonction suivante
        }
        public Machin Clone()
        {
            return ...;
        }
    }
    ce qui permet à la classe d'implémenter un interface de façon explicite tout en fournissant une méthode dont le type de retour est plus typé.

    Mais dans ton cas : si tu as une collection d'objets ayant des fonctions F avec un type de retour différent, y'a bien un moment ou tu devras tester le type réel de tes objets pour récupéréer correctement le résultat de F, non ?
    ಠ_ಠ

  19. #19
    Membre actif
    Profil pro
    Inscrit en
    Février 2006
    Messages
    413
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2006
    Messages : 413
    Points : 286
    Points
    286
    Par défaut
    Citation Envoyé par Guulh Voir le message
    [...]
    Mais dans ton cas : si tu as une collection d'objets ayant des fonctions F avec un type de retour différent, y'a bien un moment ou tu devras tester le type réel de tes objets pour récupéréer correctement le résultat de F, non ?
    Effectivement. Par exemple, lors de ma boucle foreach, je vais devoir tester le type de mon objet dans mon tableau pour savoir quel est le type d'objet retourné par ma méthode.

  20. #20
    Membre habitué Avatar de BigNic
    Profil pro
    Inscrit en
    Décembre 2004
    Messages
    195
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Décembre 2004
    Messages : 195
    Points : 154
    Points
    154
    Par défaut
    personellement j'aurai tout fait avec des interfaces genre:
    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
     
     
    interface ISearcher
    {
        List<Object> Search (string myPattern);
    }
     
    class Main
    {
        void main (params)
        {
             /*....*/
             myReturns = myRealSearcher.Search("C:\\*.*");
             foreach(Object item in myReturns)
             {
                  if(item is File)
                  {
                       /* traitement pour les fichiers */
                  }
     
                  if(item is Directory)
                  {
                        /* traitement pour les repertoires */
                  }
             }
     
         }
    }
    C'est pas parfait, mais plus simple à lire et a comprendre que des generics.
    Et de toute façon kit à devoir tester le type retourner autant renvoyer des Object.

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

Discussions similaires

  1. [PL/SQL] type de retour d'une fonction
    Par foffffa dans le forum SQL
    Réponses: 4
    Dernier message: 27/03/2008, 15h06
  2. Réponses: 3
    Dernier message: 07/02/2006, 13h26
  3. [Oracle 9.1] Types de retour d'une fonction PL/SQL
    Par ftrifiro dans le forum PL/SQL
    Réponses: 8
    Dernier message: 12/10/2005, 16h54
  4. [surcharge]changer le type de reotour d'une méthode
    Par bountykiller dans le forum C++
    Réponses: 3
    Dernier message: 28/09/2005, 11h41
  5. [type de retour dans une proc]
    Par viny dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 19/03/2005, 14h35

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