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

Langage Delphi Discussion :

Transtypage "sale"


Sujet :

Langage Delphi

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    72
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 72
    Points : 74
    Points
    74
    Par défaut Transtypage "sale"
    Bonjour,

    Je voudrais faire un truc pas trés propre dans Delphi ... Vous me dites si ca fonctionnera ou si vous avez une meilleure (plus élégante) solution.

    J'ai 2 objets, A et B, qui ne dérivent pas l'un de l'autre. J'ai une fonction qui peut renvoyer soit A soit B, suivant certaines conditions. Ces 2 objets partagent certaines propriétés communes (même nom, même type, même concept).

    Ce que je voudrais faire est récupérer le résultat de la fonction, caster ce résultat en un type A (même si c'est du B) puis faire

    TypeA(Resultat).Propriété

    sachant que même si c'est du B, la propriété existera bien quand même, mais j'aurai transtypé (ca y est je reviens en Francais) dans le mauvais type. Je sais que c'est pas trés joli joli tout ca

    Déjà, cela fonctionnera t'il?

    2. Sans me faire dériver une classe d'une autre, vous avez une solution élégante et concise (et qui fait le café) à ce petit soucis (qui n'en est pas un, je pourrais toujours me fendre d'une fonction qui test le type exact et qui renvoi la valeur de la propriété correcte en faisant le bon transtypage à chaque fois) ... Je voulais juste éviter de faire cette fonction... (remarquez j'aurai pris guère plus de temps que le temps de taper ce message!).

    On va dire que la question est pour l'intêret intellectuel (si si il y en a un) qu'elle a...

  2. #2
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    non ca ne marchera pas, c'est forcement la procedure de A qui sera appelé, sauf qu'elle manipulera les données de B, sachant que ces données ne sont pas forcement ordonées pareille que dans A.

    La solution serait l'utilisation d'une interface :
    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
     
    type
      IAouB = interface
        function Nom: string;
      end;
     
      TypeA = class(TInterfacedObject, IAouB)
      public
        function Nom: string;
      end;
     
      TypeB = class(TInterfacedObject, IAouB)
      public
        function Nom: string;
      end;
     
    implementation
     
    function TypeA.Nom: string;
    begin
      Result := 'Je suis A';
    end;
     
    function TypeB.Nom: string;
    begin
      Result := 'Moi c''est B';
    end;
    et l'utilisation :
    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
     
    function MaFonctionQuiMeRetourneAouB: IAouB;
    var
      o: TObject;
    begin
      if JeVeuxUnA then
        o := GetUnTypeA
      else
        o := GetUnTypeB
     
      if not o.getInterface(IAouB, Result) then
        Result := nil;
    end;
     
    var
      i: IAouB;
    begin
      i := MaFonctionQuiMeRetourneAouB;
      if i <> nil then
        ShowMessage(i.Nom);
      i := nil;
    end;

  3. #3
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

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

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 448
    Points
    28 448
    Par défaut
    alors techniquement ça peu fonctionner si A et B ont le même ancêtre et que les propriétés sont déclarées au même endroit dans le même ordre...par contre il n'y a aucun garde fou dans cette approche

    l'interface est en effet une bonne solution à ce genre de problèmes, sinon il faut que la fonction retourne non pas une instance de A ou B mais par exemple un record avec les propriétés désirées.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    72
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 72
    Points : 74
    Points
    74
    Par défaut
    Citation Envoyé par guillemouze Voir le message
    non ca ne marchera pas, c'est forcement la procedure de A qui sera appelé, sauf qu'elle manipulera les données de B, sachant que ces données ne sont pas forcement ordonées pareille que dans A.

    La solution serait l'utilisation d'une interface :
    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
     
    type
      IAouB = interface
        function Nom: string;
      end;
     
      TypeA = class(TInterfacedObject, IAouB)
      public
        function Nom: string;
      end;
     
      TypeB = class(TInterfacedObject, IAouB)
      public
        function Nom: string;
      end;
     
    implementation
     
    function TypeA.Nom: string;
    begin
      Result := 'Je suis A';
    end;
     
    function TypeB.Nom: string;
    begin
      Result := 'Moi c''est B';
    end;
    et l'utilisation :
    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
     
    function MaFonctionQuiMeRetourneAouB: IAouB;
    var
      o: TObject;
    begin
      if JeVeuxUnA then
        o := GetUnTypeA
      else
        o := GetUnTypeB
     
      if not o.getInterface(IAouB, Result) then
        Result := nil;
    end;
     
    var
      i: IAouB;
    begin
      i := MaFonctionQuiMeRetourneAouB;
      if i <> nil then
        ShowMessage(i.Nom);
      i := nil;
    end;
    Intéressant et clair... Mais cela peut il fonctionner si les 2 classes sont déjà dérivées d'autres classes? Genre

    TypeA = class(TAncetre, TInterfacedObject, IAouB)
    ?

    Désolé je suis un béotien en interface.

    Le "soucis" également est que ca m'oblige donc à déclarer une interface qui a toutes les propriétés communes forcément ... donc pas économique en lignes de code ... J'aurai donc tendance à aller au plus simple (à ce que je connais, mmmh c'est pas comme cela que je vais progresser) et à utiliser l'astuce du record de Paul qui me semble sympa aussi.

  5. #5
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Salut
    Citation Envoyé par Pocus Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TypeA = class(TAncetre, TInterfacedObject, IAouB)
    Euh non, pas d'héritages multiples en Delphi. TAncetre ou TInterfacedObject, mais pas les deux.

    Le record proposé par Paul me plait assez bien, sans rejeter non plus les interfaces.

    A part ça, ils ont oublié le café: Voilà ça c'est fait.

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    72
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 72
    Points : 74
    Points
    74
    Par défaut
    ok merci pour vos réponses rapides et informatives...

    J'ai tous les éléments qu'il me faut maintenant, on peut passer le fil en résolu si besoin.

  7. #7
    Membre habitué Avatar de samaury
    Homme Profil pro
    Chevalier Jedi
    Inscrit en
    Mars 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Chevalier Jedi
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2008
    Messages : 114
    Points : 141
    Points
    141
    Par défaut
    Salut
    Je ferais comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    function maFonctionSale(monObjetAouB:TObject):TypeA;
    begin
     Result:=TypeA.Create();
     if montObjetAOuB is TypeA then begin
       Result.maPropriete := TypeA(monObjetAOuB).maPropriete;
     else if montObjetAOuB is TypeB then begin
       Result.maPropriete := TypeB(monObjetAOuB).maPropriete;
     end else begin
      Result.Free();
      raise Exeception.Create('Houston...nous avons un problème');
     end;
    end;
    Pensons bien, pensons bio

  8. #8
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    Citation Envoyé par samaury Voir le message
    Salut
    Je ferais comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    function maFonctionSale(monObjetAouB:TObject):TypeA;
    begin
     Result:=TypeA.Create();
     if montObjetAOuB is TypeA then begin
       Result.maPropriete := TypeA(monObjetAOuB).maPropriete;
     else if montObjetAOuB is TypeB then begin
       Result.maPropriete := TypeB(monObjetAOuB).maPropriete;
     end else begin
      Result.Free();
      raise Exeception.Create('Houston...nous avons un problème');
     end;
    end;
    cette solution me semble pas mal aussi
    mis a part que le type de retour de la fonction n'est pas le bon, mais je suppose que c'est une faute "de frappe"

    @Pocus : le type TInterfacedObject est un type basique, qui ne fait qu'implementer les 3 fonctions de bases obligatoire d'une interface en delphi : _AddRef, _Release et _QueryInterface, mais tu peux aussi hériter de n'importe quoi, et reimplementer ces fonctions dans ta classe

  9. #9
    Membre habitué Avatar de samaury
    Homme Profil pro
    Chevalier Jedi
    Inscrit en
    Mars 2008
    Messages
    114
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Côte d'Ivoire

    Informations professionnelles :
    Activité : Chevalier Jedi
    Secteur : Finance

    Informations forums :
    Inscription : Mars 2008
    Messages : 114
    Points : 141
    Points
    141
    Par défaut
    mis a part que le type de retour de la fonction n'est pas le bon, mais je suppose que c'est une faute "de frappe"
    Oups c'est vrai :

    Result:=

    Plus sérieusement...elle est ou l'erreur, mon neurone n'arrive pas à la voir!
    Pensons bien, pensons bio

  10. #10
    Expert éminent sénior
    Avatar de Cl@udius
    Homme Profil pro
    Développeur Web
    Inscrit en
    Février 2006
    Messages
    4 878
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Matériel informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 4 878
    Points : 10 008
    Points
    10 008
    Par défaut
    Elle devrait être de type TAncetre (ou TObject).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    function maFonctionSale(monObjetAouB: TAncetre): TAncetre;

  11. #11
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    au temps pour moi, j'ai lu ta fonction en diagonale tout en gardant la question de base en tete. Ce que je voyait etait plus un truc comme ca (en reprenant ton exemple) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    function GetMaPropriete(monObjetAouB:TObject): TypeDeMaPropriete;
    begin
     if montObjetAOuB is TypeA then begin
       Result := TypeA(monObjetAOuB).maPropriete;
     else if montObjetAOuB is TypeB then begin
       Result := TypeB(monObjetAOuB).maPropriete;
     end else begin
      raise Exeception.Create('Houston...nous avons un problème');
     end;
    end;
    mais a faire pour chaque propriete commune, donc un peu lourdingue.

    Ce que tu fais, c'est creer dans tout les cas un objet A, qui aura les proprietes de l'objetAouB, ce qui n'est pas forcement jouable (sinon il n'y aurait pas forcement d'interet a avoir un typeB).
    Apres, les infos sur les structures reelles sont trop legere pour pouvoir faire des suppositions viables.

    Conclusion : avec ce que l'on sait du probleme, je pencherais preferablement pour l'interface qui me semble plus propre & adapté (malgré les lourdeurs des interfaces delphi necessitant des fonctionnalités de comptage non necessaires dans ce cas)

  12. #12
    Candidat au Club
    Profil pro
    Inscrit en
    Novembre 2010
    Messages
    3
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3
    Points : 4
    Points
    4
    Par défaut
    Tu as aussi la possibilité d'utilisé l'unité 'TypInfo' pour copier les propriétés d'un objet ver un autre. Si ton typecast est purement interne alors TypInfo est pour toi. Je veux dire qu'avec TypInfo tu peux copier un object vers un autre seulement en te basant sur le nom/type des propriétés. très pratique pour passer d'une version de fichier à une autre ( par example). Ou même pour ne copier que certaines props de l'objet.

    Dans TypInfo tu as:

    GetPropList( aSource, PPropList ): tu as la liste de props du composant aSource sur un TProplist (dont la mémoire est innitialisé automatiquement mais nécéssite une libération manuelle)

    PropCount := GetTypeData( MyInputClass.ClassType.ClassInfo)^.PropCount ;
    Tu as le nombres de propriétés de ta classe d'entrée

    Le résultat de GetPropList, permet de tester une propriété de 0 à PropCount tu as un record

    setprop: pointeur vers une procédure qui permet de définir un paramètre ( if Nil then props is read only...)
    getprop: pointeur vers une fonction ou une variable qui permet d'obtenir la prop(devrait toujours être valide)...

    Bref... etc etc

    Avec TypInfo tu peux caster des objets de manières complexe, tu peux tout à fait copier les props d'une classe vers les autres props d'une classe si elles portent le même nom(même sans relation d'héritage). Par contre il faut une logique interne à ton projet, ce ne peut pas être générique mais seulement apliquable à tes besoins.

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Septembre 2006
    Messages
    72
    Détails du profil
    Informations personnelles :
    Âge : 55
    Localisation : France

    Informations forums :
    Inscription : Septembre 2006
    Messages : 72
    Points : 74
    Points
    74
    Par défaut
    Je pensais que ca ne fonctionnait qu'avec les prps publiées. J'ai envisagé d'utiliser les RTTI pour pas mal de chose, mais cette limitation m'a toujours freiné.

  14. #14
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    Citation Envoyé par Pocus Voir le message
    Je pensais que ca ne fonctionnait qu'avec les prps publiées. J'ai envisagé d'utiliser les RTTI pour pas mal de chose, mais cette limitation m'a toujours freiné.
    Il me semble qu'en delphi7, seule les property published (et a condition d'avoir la directive {$M+}, sauf pour les composants) sont accessibles en RTTI, et que dans une version superieur (2005, 200X, ... ?, je ne sais plus laquelle), tout est accessible via RTTI.

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