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 :

Interfaces, dérivés et appelants : problème de cast implicite


Sujet :

C#

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    837
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2003
    Messages : 837
    Par défaut Interfaces, dérivés et appelants : problème de cast implicite
    Bonjour à tous,

    Je suis face à un souci concernant l'archi sur laquelle je travaille.
    Souhaitant utiliser au mieux les interfaces et le polymorphisme, je me retrouve dans une situation où j'ai une interface de base, et des interfaces dérivées.
    J'ai une fonction par interface dérivée attendant en paramètre un modele de type Iquelquechose mais toutes les fonctions portent le même nom (admettons "Save" pour l'exemple).
    Jusque là, tout va bien. Si je fais appel à ma fonction Save en utilisant n'importe quel model à partir du moment où ceux ci implémentent bien une des interfaces, je suis routé vers le bon traitement.

    Maintenant, j'ai un souci si jamais je créé une fonction qui va venir ajouter une couche au dessus.
    Exemple : Je créé une fonction TraitementMetier qui va commencer par faire un traitement X puis fait appel à la fonction Save puis fait un traitement Y.
    Donc ma fonction traitementMetier attend un model de type IBase qui est l'interface mère dont héritent toutes les interfaces citées plus haut.

    Si j'execute cette fonction, cela appellera toujours la fonction Save dont le paramètre attend un IBase et ne routera jamais vers les traitements spécifiques des autres interfaces.
    Je pense que cela vient du fait que TraitementMetier attendant un paramètre de type IBase, force l'appel à Save(IBase m) mais comment contourner ce problème du coup ?
    C'est dommage car cela m'évitais de devoir tester si le type de mon model implémente telle interface alors je force le cast dans ce type sinon si c'est telle autre interface etc...

    Auriez vous une idée ?

  2. #2
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Hello,

    problématqiue fréquente Formulé autrement : comment avoir un comportement polymorphique en dehors d'une hiérarchie de classe ?

    Ce que tu recherches, ça s'appelle le double dispatch. Certains langages ont cette fonctionnalité de base, d'autres pas (dont C++, C# et Java).
    Il existe un Design Pattern pour cela: le visitor. Je te laisse googler.

    Depuis C# 4, le mot clé dynamic permet de se passer de visitor (au prix d'une type-safety un peu moindre). Tu trouveras plus de détails ici, ou les deux solutions sont abordées.

  3. #3
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    837
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2003
    Messages : 837
    Par défaut
    Salut et merci pour ta réponse.
    Alors pour tout te dire, j'ai triché un peu ^^ je suis en VB.Net
    J'ai posté dans le forum C# parce qu'en général c'est plus réactif au vu de la communauté plus grande.
    Je n'ai à priori pas bien capté le pattern mais bon je vais essayer de plancher là dessus et voir si j'arrive à m'en sortir avec.
    Merci du tuyau en tout cas.

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

    Informations professionnelles :
    Activité : .NET / SQL SERVER

    Informations forums :
    Inscription : Avril 2007
    Messages : 14 204
    Par défaut
    moi en voyant le topic j'ai regardé un peu et j'ai cru comprendre qu'on avait pas ce problème en vb.net, et que nous n'avions pas le mot clé dynamic pour cette raison

    j'aimerais bien tester pour voir ce que ca donne mais je n'ai pas trop compris le schéma de tes interfaces et classes ...
    Cours complets, tutos et autres FAQ ici : C# - VB.NET

  5. #5
    Membre éclairé
    Profil pro
    Inscrit en
    Février 2003
    Messages
    837
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations forums :
    Inscription : Février 2003
    Messages : 837
    Par défaut
    Ah là tu m'interesses (et au passage : j'ai voulu chercher sur le net mais honnêtement je ne savais pas comment poser le probleme sur google... Par quels genre de mots clés t'es passé pour avoir des résultats parlant de cette problématique ?)

    Sinon, concernant les tests, voilà comment tu peux procéder (c'est très rapide à faire) :
    Tu créés un projet Windows Forms classique avec 3 répertoires :
    - Interfaces
    - Objects
    - Logic

    Dans Interfaces, tu créés 2 interfaces :
    - IBase avec Nom as string et prenom as string
    - IDerivee qui hérite de IBase et tu ajoutes une property DateNaissance as datetime

    Dans Objects, tu créés 2 objets :
    - PersonBase qui implémente IBase
    - PersonDerivee qui implémente IDerivee

    Dans Logic, tu créés 2 classes :
    - PersonLogic dans laquelle tu créés deux méthodes save
    --- save(p as IBase) : cette sub fait juste messagebox.show("Base")
    --- save(p as IDerivee) : cette sub fait juste messagebox.show("derivee")
    - BusinessLogic dans laquelle tu créés la méthode suivante
    --- DoBusinessWork(p as IBase) dans laquelle tu executes les points suivants :
    -------+ messagebox.show("pré traitement")
    -------+ tu fais appel à PersonLogic.save(p)
    -------+ messagebox.show("post traitement")

    Enfin, sur ta form, tu ajoutes deux boutons dont les événements font le traitement suivant :
    - l'un va créer une instance de PersonBase et faire appel à businessLogic.DoBusinessWork en l'envoyant en paramètre
    - l'autre va créer une instance de PersonDerivee et faire appel à businessLogic.DoBusinessWork en l'envoyant en paramètre

    Tu verras que dans les deux cas, le messagebox.show qui sera appelé sera celui qui affiche "Base" et non l'un base et l'autre derivée.

  6. #6
    Membre Expert Avatar de Guulh
    Homme Profil pro
    Inscrit en
    Septembre 2007
    Messages
    2 160
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Septembre 2007
    Messages : 2 160
    Par défaut
    Citation Envoyé par zax-tfh Voir le message
    Ah là tu m'interesses (et au passage : j'ai voulu chercher sur le net mais honnêtement je ne savais pas comment poser le probleme sur google... Par quels genre de mots clés t'es passé pour avoir des résultats parlant de cette problématique ?)
    Cherche "visitor pattern", tout simplement. C'est l'un des principaux design patterns. Ma remarque ne sous-entendait rien de péjoratif, juste que tu trouveras pas mal de littérature sur le net sans que je doive tout décrire ici
    En deux mots, disons que t'as une classe mère M, et deux filles F1 et F2. Si tu veux mettre ton comportement polymorphique directement dans les classes, ça donne ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class M { public abstract string F(); }
     
    class F1 : M { public override string F() { return "je suis F1"; } }
    class F2 : M { public override string F() { return "je suis F2"; } }
    Basique donc. Par contre, si tu veux que les methodes F soient en dehors, le pattern visiteur consiste à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class M { public abstract Accept(Visitor v); }
    class F1 { public override Accept(Visitor v) { v.Visit1(this); }
    class F2 { public override Accept(Visitor v) { v.Visit2(this); }
    public class Visitor
    {
      public void Visit1(F1 obj) { ... }
      public void Visit2(F2 obj) { ... }
    }
     
    M obj = new F1();
    var v = new Visitor();
    obj.Accept(v); // va exécuter Visit1
    Tu vois ? Ca permet de mettre dans une seule classe (ici Visitor) les méthodes spécifiques a chaque sous-type, et c'est la méthode accept qui va rediriger (dispatch en anglais) vers la bonne en fonction du type réel de l'objet.

Discussions similaires

  1. [CASTS]problème de cast de Time
    Par DeVoN dans le forum Langage
    Réponses: 7
    Dernier message: 22/02/2006, 17h24
  2. [JDBC Driver][JSTL] Problème de cast de données
    Par GyLes dans le forum PostgreSQL
    Réponses: 1
    Dernier message: 27/09/2005, 10h00
  3. problème de cast!
    Par LaseLiep dans le forum Langage
    Réponses: 3
    Dernier message: 03/06/2005, 09h30
  4. Problème de cast/serialization/externalization ?
    Par Linlin dans le forum CORBA
    Réponses: 1
    Dernier message: 06/12/2004, 16h46
  5. [C#] Problème de casting de @IDENTITY
    Par bilb0t dans le forum Accès aux données
    Réponses: 7
    Dernier message: 03/09/2004, 09h42

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