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 :

Listes génériques de types génériques


Sujet :

Langage Delphi

  1. #1
    Membre du Club Avatar de CoyotteDundee
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2008
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2008
    Messages : 54
    Points : 47
    Points
    47
    Par défaut Listes génériques de types génériques
    Bonjour à toutes et tous,

    Je commence à "jouer" avec les types génériques et j'ai un petit problème de syntaxe de déclaration avec Delphi Xe8.
    J'ai simplifié le problème avec le code exemple suivant :

    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
     
    uses generics.collections;
     
    type
      TBaseType<T> = class
      private
        procedure SetValue(const Value: T);
        protected
        FValue: T;
        public
        property Value: T read FValue write SetValue;
      end;
     
      TInt = class( TBaseType<integer> );
      TString = class( TBaseType<string> );
     
      TBaseList<T1:TBaseType<T>> = class( TObjectList<T1>)
       function DoSomething: boolean;
      end;
     
      TIntList = class( TBaseList<TInt> );
    Comme on le voit, TBaseType est spécialisé en TInt et TString. Pas de soucis jusque là.
    TBaseList est une liste basée du TObjectList implémentant une fonctionnalité supplémentaire.

    Le problème se situe au niveau de la déclaration de TBaseList. (Ligne 17) Delphi se plaint : "Undeclared Identifier :'T'" ainsi que "Type parameter 'T' must be a class type".
    J'ai essayé plusieurs variantes de déclaration sans trouver celle qui satisferait le compilateur.

    Quelqu'un peut-il m'expliquer où se situe mon erreur ?

    Merci d'avance,

    Coyotte

  2. #2
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 441
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 441
    Points : 3 076
    Points
    3 076
    Par défaut
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
     
    unit Unit2;
     
    interface
     
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
      System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
     
    type
      TForm2 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form2: TForm2;
     
    implementation
     
    {$R *.dfm}
     
    uses generics.collections;
     
    type
      TBaseType<T> = class
      private
        procedure SetValue(const Value: T);
      protected
        FValue: T;
      public
        property Value: T read FValue write SetValue;
      end;
     
      TInt = class(TBaseType<integer>);
      TString = class(TBaseType<string>);
     
      TBaseList<T> = class(TList<T>)
        function DoSomething: boolean;
      end;
     
      TIntList = class(TBaseList<TInt>);
     
      { TBaseType<T> }
     
    procedure TBaseType<T>.SetValue(const Value: T);
    begin
      FValue := Value;
    end;
     
    { TBaseList<T1> }
     
    function TBaseList<T>.DoSomething: boolean;
    begin
      //
    end;
     
    procedure TForm2.Button1Click(Sender: TObject);
    var
      L: TBaseList<TInt>;
    begin
      L := TBaseList<TInt>.Create;
      L[L.Add(TInt.Create)].Value := 12;
      ShowMessage(IntToStr(L.First.Value));
      L.Free;
    end;
     
    end.
    J-L aka Papy pour les amis

  3. #3
    Membre du Club Avatar de CoyotteDundee
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2008
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2008
    Messages : 54
    Points : 47
    Points
    47
    Par défaut
    Bonjour Papy,

    Merci pour la réponse complète et rapide...
    J'ai une petite contrainte supplémentaire par rapport à ton code :
    Je souhaite que la liste TBaseList ne puisse gérer que des classes descendantes de TBaseType... Et c'est là que cela coince pour moi.

    Par contre, très élégante la construction
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    L[L.Add(TInt.Create)].Value := 12;
    Je n'y avait jamais pensé...

    Coyotte

  4. #4
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 534
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 534
    Points : 25 082
    Points
    25 082
    Par défaut
    Lorsque je suis passé de D7 à BCB2007 puis XE3, j'ai découvert les templates : STL list<> et VCL TList<>
    A mon retour en Delphi XE2, j'ai tenté aussi les génériques Delphi, je crois que le sujet "Problème d'héritage avec les génériques."
    c'est exactement le même soucis d'imbrication de type générique

    Contraintes dans les génériques

    Au mieux, tu peux forcer un type classe mais un type de class générique précise
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TBaseList<T: class> = class(TObjectList<T>)
    tu peux créer un super ancêtre non générique qui forcera la chaine
    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
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    type
      TBaseTypeAncestor = class abstract(TObject);
     
      TBaseType<T> = class(TBaseTypeAncestor)
      private
        procedure SetValue(const Value: T);
      protected
        FValue: T;
      public
        property Value: T read FValue write SetValue;
      end;
     
      TInt = class( TBaseType<integer> );
      TString = class( TBaseType<string> );
     
      TBaseList<T: TBaseTypeAncestor> = class(TObjectList<T>)
       function DoSomething: boolean;
      end;
     
      TIntList = class(TBaseList<TInt>);
      TUncompiledList = class( TBaseList<TObject> );
     
    procedure TZooThomVCLMainForm.btn1Click(Sender: TObject);
    var
      L: TIntList;
      LU: TUncompiledList;
    begin
      L := TIntList.Create(True);
      try
        L[L.Add(TInt.Create)].Value := 12;
        ShowMessage(IntToStr(L.First.Value));
      finally
      end;
      L.Free();
     
      LU := TUncompiledList.Create(True);
      LU.Free();
    end;
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  5. #5
    Membre du Club Avatar de CoyotteDundee
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2008
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2008
    Messages : 54
    Points : 47
    Points
    47
    Par défaut
    Super !
    Merci ShaiLeTroll
    J'ai une base pour démarrer maintenant...
    Je marque le sujet comme étant résolu.

    Merci à vous deux,

    Coyotte

  6. #6
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 441
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 441
    Points : 3 076
    Points
    3 076
    Par défaut
    pas testé mais ça doit le 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
     
    uses generics.collections;
     
    type
     
      IBaseType = Interface
     
      End;
     
      TBaseType<T> = class(TInterfacedObject, IBaseType)
      private
        procedure SetValue(const Value: T);
      protected
        FValue: T;
      public
        property Value: T read FValue write SetValue;
      end;
     
      TInt = class(TBaseType<Integer>, IBaseType);
      TString = class(TBaseType<string>, IBaseType);
     
      TBaseList<T: IBaseType, constructor> = class(TList<T>)
        function DoSomething: boolean;
      end;
     
      TIntList = class(TBaseList<TInt>);

    Testé, ça fonctionne
    J-L aka Papy pour les amis

  7. #7
    Membre du Club Avatar de CoyotteDundee
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2008
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2008
    Messages : 54
    Points : 47
    Points
    47
    Par défaut
    Merci Papy,

    En tout cas, ça compile...
    J'ai donc deux options pour résoudre mon problème, ce qui est tout de même assez confortable

    Question :
    Pourquoi re-déclares-tu IBaseType dans les déclarations de TInt et TString ?
    Cette interface est déjà associée à l'ancêtre TBaseType, non ?
    Il y a-t-il une raison particulière pour ce faire ?


    Coyotte

  8. #8
    Membre expert

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Novembre 2007
    Messages
    3 441
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 62
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Novembre 2007
    Messages : 3 441
    Points : 3 076
    Points
    3 076
    Par défaut
    aucune raison, je suis juste allé un peu trop vite dans mon écriture ... tu peux les enlever
    J-L aka Papy pour les amis

  9. #9
    Membre du Club Avatar de CoyotteDundee
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2008
    Messages
    54
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Finance

    Informations forums :
    Inscription : Juin 2008
    Messages : 54
    Points : 47
    Points
    47
    Par défaut
    ...C'est bien ce que laissait à penser mon test... :-)

    L'usage de l'interface permet de s'affranchir de l'obligation d'héritage de base pour toutes les classes manipulées, ce qui peut être un avantage dans certains cas.
    Je vais pouvoir retourner plancher sur ma structure de classes qui va drôlement être simplifiée maintenant.

    Merci,

    Coyotte

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

Discussions similaires

  1. [Débutant] Utilisation type générique : List<T>
    Par Leilou dans le forum C#
    Réponses: 5
    Dernier message: 12/08/2013, 15h23
  2. Réponses: 5
    Dernier message: 01/02/2011, 15h34
  3. list générique et type
    Par cedricg1976 dans le forum C#
    Réponses: 13
    Dernier message: 15/07/2009, 17h24
  4. Liste générique de types génériques
    Par le2tbomi dans le forum VB.NET
    Réponses: 7
    Dernier message: 17/07/2008, 23h16
  5. Réponses: 12
    Dernier message: 23/09/2006, 12h12

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