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

Contribuez Delphi Discussion :

Assistants de classe/enregistrement (Class/record Helpers), D2009 et supérieur


Sujet :

Contribuez Delphi

  1. #1
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut Assistants de classe/enregistrement (Class/record Helpers), D2009 et supérieur
    Bonjour à tous

    A la lecture de certains sujets ces derniers jours, il m'a semblé que les assistants de classe ou d'enregistrement étaient largement méconnus et qu'une discussion traitant spécifiquement de ce sujet, mais surtout avec des exemples concrets, serait intéressante

    Très courte introduction sur les assistants de classe (Class Helpers)
    Les assistants de classe ne sont rien d'autres que l'ajout de mécanismes d'accès aux données d'une classe déterminée. C'est en sorte une amélioration de l'encapsulation (pour parler POO) de cette classe.
    Il n'est pas possible d'ajouter de nouvelles propriétés par l'intermédiaire d'un assistant mais uniquement de la lecture/écriture des propriétés existantes.

    Vous n'avez rien compris ? Attendez !
    Voici un exemple concret que tout le monde à déjà taper des centaines de fois : ExtractFilePath(Application.ExeName);. Ne serait-il pas intéressant de pouvoir simplement invoquer Application.Path ?

    Voici la déclaration et l'implémentation d'un assistant de TApplication :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type
      TApplicationHelper = class Helper for TApplication
        function Path(aExcludeTrailingDelimiter: boolean = FALSE) :TFileName;
      end;
     
    function TApplicationHelper.Path(aExcludeTrailingDelimiter: boolean): TFileName;
    begin
      Result := ExtractFilePath(ExeName);
     
      if aExcludeTrailingDelimiter then
        Result := ExcludeTrailingPathDelimiter(Result);
    end;
    et dans nos applications :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //Nous pouvons remplacer ceci...
    MyApp := ExtractFilePath(Application.ExeName) +'MonApp.exe';
    //...par cela
    MyApp := Application.Path +'MonApp.exe';
     
    //et même...
    Path := ExcludeTrailingPathDelimiter(ExtractFilePath(Application.ExeName));
    //...par...
    Path := Application.Path(TRUE);
    C'est plus clair

    Les assistants d'enregistrement
    Alors que pour une classe on pourrait envisager d'autres possibilités comme TUnObjet=class(UneUnité.TUnObjet), les héritages d'enregistrement ne sont pas possibles et dans ce cas, les assistants sont une réelle aide. Ils fonctionnent la même chose que pour les classes.

    Un exemple avec TRect.
    J'ai souvent eu à connaitre les quatre coins d'un rectangle, mais l'implémentation existante ne permet de récupérer sous la forme d'un TPoint que les coins TopLeft et BottomRight.

    Pour ajouter les deux autres:
    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
    type
      TRectHelper = record Helper for TRect
        function TopRight   :TPoint;
        function BottomLeft :TPoint;
      end;
     
    function TRectHelper.BottomLeft: TPoint;
    begin
      Result.X := Left;
      Result.Y := Bottom;
    end;
     
    function TRectHelper.TopRight: TPoint;
    begin
      Result.X := Right;
      Result.Y := Top;
    end;
    Attention, il ne s'agit pas de disserter sur telle ou telle proposition, mais vraiment de générer une bibliothèque de codes utiles, avec exemples.
    Répondre C'est super ! ou à l'inverse Comment je pourrais faire ça ? n'est pas le but ! Mais si un code vous semble intéressant (voire carrément utile), n'hésitez pas à voter

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut Ajouter le test "vide" sur un TEdit
    Pour tester si un TEdit contient ou non du texte:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    type
      TEditHelper = class Helper for TEdit
      private
        function  GetEmpty: boolean;
      public
        property  Empty :boolean read GetEmpty;
      end;
     
    function TEditHelper.GetEmpty: boolean;
    begin
      Result := Text = '';
    end;
    Nous remplacerons ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if (Edit3.Text <> '') And (Edit4.Text = '') And (Edit5.Text = '') And...
    par:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if not Edit3.Empty And Edit4.Empty And Edit5.Empty And...

  3. #3
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut Path, Name, Ext depuis un TFileName
    Plus intéressant, la manipulation des chaînes qui se gère comme un enregistrement. Ici, l'extraction des données d'un TFileName (type string):

    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
      TFileNameHelper = record Helper for TFileName
      private
        function  GetEmpty: boolean;
        function  GetExt: string;
        function  GetName: string;
        function  GetPath: string;
        procedure SetExt(const Value: string);
      public
        property  Empty :boolean read GetEmpty;
        property  Path :string read GetPath;
        property  Name :string read GetName;
        property  Ext :string read GetExt write SetExt;
      end;
     
    function TFileNameHelper.GetExt: string;
    begin
      Result := ExtractFileExt(Self);
    end;
     
    function TFileNameHelper.GetEmpty: boolean;
    begin
      Result := self = '';
    end;
     
    function TFileNameHelper.GetName: string;
    begin
      Result := ExtractFileName(Self);
    end;
     
    function TFileNameHelper.GetPath: string;
    begin
      Result := ExtractFilePath(Self);
    end;
     
    procedure TFileNameHelper.SetExt(const Value: string);
    begin
      Self := ChangeFileExt(Self, Value);
    end;
    On remarque ici que Self représente la chaîne.

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut Lecture/écriture multichaînes dans la base des registres (MULTI_SZ)
    La lecture/écriture de valeurs multichaînes dans la base des registres n'a jamais été implémentée dans TRegistry ! Voici de quoi palier à cette absence.
    Les chaînes sont séparées par #0 et la donnée se termine par #0#0.

    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
    type
      TRegistryHelper = class Helper for TRegistry
      public
        function  ReadMultiString(const aName: string): string;
        procedure WriteMultiString(const aName: string; aValue: string);
      end;
     
    function TRegistryHelper.ReadMultiString(const aName: string): string;
    var
      i: integer;
    begin
      SetLength(Result, GetDataSize(aName) div SizeOf(Char));
      ReadBinaryData(aName, Result[1], GetDataSize(aName));
     
      for i := 1 to Length(Result) do
        if Result[i] = #0 then
          Result[i] := #13;
    end;
     
    procedure TRegistryHelper.WriteMultiString(const aName: string; aValue: string);
    begin
      aValue := StringReplace(aValue, #13, #0, [rfReplaceAll]) +#0;
      RegSetValueEx(CurrentKey, PChar(aName), 0, REG_MULTI_SZ, PChar(aValue), Length(aValue) *SizeOf(Char));
    end;
    La lecture par ReadBinaryData ne pose pas de problème, mais il faut obligatoirement passer par l'API RegSetValueEx pour que la donnée soit définie en MULTI_SZ.

  5. #5
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 552
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 552
    Points : 3 918
    Points
    3 918
    Par défaut
    Salut

    Dans l'idée, C'est proche du Design Pattern Décorateur, non ?
    C'est valable depuis quelle version de Delphi ?

    L'article soulève un sujet assez rarement discuté, c'est une bonne idée.

    @+

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  6. #6
    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 430
    Points
    28 430
    Par défaut
    les class helper ont été introduit dans Delphi for .Net afin d'ajouter des méthodes à des objets .Net

    je trouve la syntaxe pas très élégante, à mon avis elle est à éviter pour éviter les confusions. Exemple:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    type
      TMonObject = class
        function Value: Integer;
      end;
     
    var
      o: TMonObject;
    begin
      o := TMonObject.Create;
      o.Eval('10');
    end;
    quand on regarde ce code on est tout de même assez surpris que ça compile...il faut trouver le class helper qui déclare la méthode Eval pour comprendre ce qu'il se passe.

    C'est théoriquement à utiliser uniquement sur des classes objets qu'on ne peut pas dériver - par exemple les propriétés objets d'un composant Memo.Lines - mais s'il est possible de dériver l'objet il est préférable à mon sens de le faire.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  7. #7
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 552
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 552
    Points : 3 918
    Points
    3 918
    Par défaut
    Salut

    Je précise que je n'ai pas Delphi pour .Net et n'ai pas travaillé avec non plus.

    quand on regarde ce code on est tout de même assez surpris que ça compile...il faut trouver le class helper qui déclare la méthode Eval pour comprendre ce qu'il se passe.
    C'est vrai que découvrir cela dans du code peut donner des sueurs froides mais avec le Ctrl+Click, on retrouve la définition, non ?

    C'est théoriquement à utiliser uniquement sur des classes objets qu'on ne peut pas dériver - par exemple les propriétés objets d'un composant Memo.Lines - mais s'il est possible de dériver l'objet il est préférable à mon sens de le faire.
    Tout à fait d'accord avec toi, disséminer des caractéristiques de classes au jour le jour n'est sans doute pas une bonne chose. La lecture du code d'une classe devrait donner toutes les informations à son sujet. Est-ce que l'explorateur de classe de Delphi for .Net nous aide en rattachant graphiquement les helpers à leur classe respective dans la hiérarchie, ceci de façon à les voir directement ?

    J'ai le souvenir d'un cas, je voulais rajouter une fonction à un DBGrid sans créer un nouveau composant car c'était un cas isolé et créer un nouveau composant avec toutes la plomberie que cela suppose m'enquiquinnait un peu. Etant sous D7 à l'époque, j'ai trouvé une solution "démoniaque" : j'ai créé une classe TMyDBGrid dérivée de TDBGrid avec la fonction MaFonction, pour l'appeler, il suffisait donc de faire un cast sauvage TMyDBGrid(DBGrid).MaFonction.

    C'est une forme primitive de helper mais cela m'avait bien dépanné, cette solution ne permet pas d'ajouter de nouveaux champs.

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  8. #8
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    C'est théoriquement à utiliser uniquement sur des classes objets qu'on ne peut pas dériver - par exemple les propriétés objets d'un composant Memo.Lines - mais s'il est possible de dériver l'objet il est préférable à mon sens de le faire.
    Si l'héritage est applicable, bien sûr qu'il faut l'utiliser, mais cela veut dire qu'on maîtrise la hiérarchie des classes et la création des objets. Pouvoir agir sur un ancêtre commun, dont on n'a pas le contrôle (voire même pas les sources) est un plus indéniable

    Quant aux assistants d'enregistrement, leur utilité est encore plus flagrante puisque l'héritage est impossible !

    Citation Envoyé par e-ric Voir le message
    La lecture du code d'une classe devrait donner toutes les informations à son sujet.
    Oui, mais même sans assistant, c'est impossible sans remonter dans les classes ancêtres. Et je ne parle pas des interfaces

    Citation Envoyé par e-ric Voir le message
    Etant sous D7 à l'époque, j'ai trouvé une solution "démoniaque" : j'ai créé une classe TMyDBGrid dérivée de TDBGrid avec la fonction MaFonction, pour l'appeler, il suffisait donc de faire un cast sauvage TMyDBGrid(DBGrid).MaFonction.
    Et si tu l'avais déclaré ainsi : TDBGrid = class(DBGrids.TDBGrid), tu n'aurais même pas eu besoin de transtypage

  9. #9
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 552
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 552
    Points : 3 918
    Points
    3 918
    Par défaut
    Et si tu l'avais déclaré ainsi : TDBGrid = class(DBGrids.TDBGrid), tu n'aurais même pas eu besoin de transtypage
    Je ne comprends pas trop, là.

    je rappelle que j'ai fait cela en D7.

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  10. #10
    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 430
    Points
    28 430
    Par défaut
    Citation Envoyé par e-ric Voir le message
    Je ne comprends pas trop, là.

    je rappelle que j'ai fait cela en D7.
    c'est simple, tu peux surcharger les composants de la VCL dans le code sans avoir besoin de les enregistrer à partir du moment où ils portent le même nom...exemple:

    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
     
    type
      TForm = class(Forms.TForm)
        constructor Create(AOwner: TComponent); override;
      end;
     
      TForm1 = class(TForm)
      private
        { Déclarations privées }
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    constructor TForm.Create(AOwner: TComponent);
    begin
      inherited;
      ShowMessage('je suis ici !');
    end;
    et tu peux faire ça pour tout, TButton = class(StdCtrls.TButton), ... tu peux même placer cette classe dans une autre unité pour peu qu'elle soit présente après le composant original dans le Uses de ta fiche.

    exemple, ExButtons.pas qui redéclare TButton, placé après StdCtrls dans le uses :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls, ExButtons;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  11. #11
    Membre expert
    Avatar de e-ric
    Homme Profil pro
    Apprenti chat, bienfaiteur de tritons et autres bestioles
    Inscrit en
    Mars 2002
    Messages
    1 552
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Apprenti chat, bienfaiteur de tritons et autres bestioles

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 552
    Points : 3 918
    Points
    3 918
    Par défaut
    En fait, on crée une classe descendante de même nom que l'ancêtre en jouant sur les portées d'unité.

    C'est sympa mais cela ne doit pas améliorer la compréhension si le code est déjà merdique. A ne pas laisser entre toutes les mains...

    M E N S . A G I T A T . M O L E M
    Debian 64bit, Lazarus + FPC -> n'oubliez pas de consulter les FAQ Delphi et Pascal ainsi que les cours et tutoriels Delphi et Pascal

    "La théorie, c'est quand on sait tout, mais que rien ne marche. La pratique, c'est quand tout marche, mais qu'on ne sait pas pourquoi. En informatique, la théorie et la pratique sont réunies: rien ne marche et on ne sait pas pourquoi!".
    Mais Emmanuel Kant disait aussi : "La théorie sans la pratique est inutile, la pratique sans la théorie est aveugle."

  12. #12
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut Pointeur sur Self
    Il est fréquent de créer des objets et de les ajouter à des listes. L'ennui est qu'il faut déclarer une variable temporaire pour cela.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    procedure NewItem(aList :TStrings);
    var
      Tmp :TMyItem;
     
    begin
      Tmp := TMyItem.Create;
      Tmp.OneProperty := 123;
      aList.AddObject('Nouvel élément', Tmp);
    end;
    Mais à l'aide d'un assistant de TObject, il est possible de récupérer le pointeur Self et ainsi de se contenter d'un with..do sans déclaration.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    type
      TObjectHelper = class Helper for TObject
      public
        function MySelf :pointer;
      end;
     
    function TObjectHelper.MySelf: pointer;
    begin
      Result := Self;
    end;
    Nous pourrons alors écrire le code précédent ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    procedure NewItem(aList :TStrings);
    begin
      with TMyItem.Create do
      begin
        OneProperty := 123;
        aList.AddObject('Nouvel élément', MySelf);
      end;
    end;
    ps: Un code plus ou moins similaire avait été proposé par Paul Toth, mais je n'ai pas retrouvé le sujet

  13. #13
    Membre expérimenté

    Homme Profil pro
    Inscrit en
    Mars 2004
    Messages
    897
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Marne (Champagne Ardenne)

    Informations professionnelles :
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mars 2004
    Messages : 897
    Points : 1 561
    Points
    1 561
    Par défaut
    Dès la sortie de Delphi 2005, Laurent Dardenne avait déjà abordé le sujet qu'il a ensuite officialisé avec cette entrée dans la FAQ
    Pensez à utiliser les tags dans le titre.
    Avant de poser une question reportez-vous à la FAQ Delphi
    Respectez les règles du forum.

  14. #14
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    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 452
    Points : 24 863
    Points
    24 863
    Par défaut
    En D7, j'avais mis aussi une méthode ItSelf pour mes With sur mes objets OR qui était la base de tout objet métier !

    le with en debug c'est assez retord comme dans le sujet Debug d'une requête créée dynamiquement (with TADOQuery.Create(Application) do) !

    Et le sujet c'est A la recherche de l'adresse du With perdue (Delphi amusant)

    @Andnotor
    J'aime beaucoup le TFileNameHelper !
    Pour le moment je suis sous C++Builder et je ne sais pas faire de class helper mais si je repasse sous Delphi, ce genre de chose me plait énormément !
    GetEmpty , en C++Builder, il existe IsEmpty() sur la String et donc implicitement sur TFileName

    Quand tu fais un CTRL+Clic sur Empty du TEditHelper, l'IDE arrive à retrouver le code associé du GetEmpty ?
    Parce que si tu reprends le code d'un autre développeur qui a massivement pratiqué ce type d'extension, faut que le nouveau développeur puisse s'y retrouver facilement (oui, tu vas me dire qu'il y a de la documentation mais pour cela faut déjà la trouver et la lire)
    je pense par exemple à C++Builder, il a parfois un peu de mal à me retrouver les macros

    Citation Envoyé par e-ric Voir le message
    Dans l'idée, C'est proche du Design Pattern Décorateur, non ?
    Le Décorateur effectivement apporte à son objet original de nouveaux comportements et surtout les décorateur sont chainés

    Par contre un Décorateur ne décore que l'instance qu'on lui a associé et non la classe !
    Un Décorateur peut avoir ses propres propriétés d'instance,
    Un Class Helper, j'ai toujours pas bien compris cette phrase : Un type d'assistance peut ne pas déclarer de données d'instance, mais les champs de classe sont autorisés.

    Est-ce pareil pour le class helper ?
    Ou le compilateur refuse deux class helper sur la même classe (ce qui serait mieux pour éviter dans avoir qui traine un peu partout)
    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

  15. #15
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 688
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 688
    Points : 13 117
    Points
    13 117
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Quand tu fais un CTRL+Clic sur Empty du TEditHelper, l'IDE arrive à retrouver le code associé du GetEmpty ?
    Oui, oui, tu retrouves la déclaration. Le debugger y passe aussi !

    Citation Envoyé par ShaiLeTroll Voir le message
    Parce que si tu reprends le code d'un autre développeur qui a massivement pratiqué ce type d'extension, faut que le nouveau développeur puisse s'y retrouver facilement
    C'est comme pour tout, il faut être strict sur les appellations. Si tu "assistes" un type déclaré dans Forms.pas, crée une unité Forms.Helpers.pas
    Les assistants sont là pour accélérer l'édition. Les disséminer dans plusieurs unités n'a pas d'intérêt (j'en ai eu besoin aujourd'hui, j'en aurai encore certainement besoin un jour ou l'autre).

    Citation Envoyé par ShaiLeTroll Voir le message
    La documentation est dans les choux ! Peut ne pas devrait être ne peut pas et la définition des champs de classe me semble... bizarre (ou ma terminologie n'est pas la leurs)

    Non, il n'est pas possible de créer des variables d'instance. Ceci n'est pas supporté :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      TObjectHelper =class helper for TObject
      private
        V1 :integer;
      end;
    mais les variables de classe fonctionne :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
      TObjectHelper = class helper for TObject
      private
        class var V1 :integer;
      end;
    Citation Envoyé par ShaiLeTroll Voir le message
    Est-ce pareil pour le class helper ? Ou le compilateur refuse deux class helper sur la même classe (ce qui serait mieux pour éviter dans avoir qui traine un peu partout)
    Ce serait de l'héritage d'assistant
    Non, ce n'est pas supporté.

    @Pascal Jankowski
    C'est juste

  16. #16
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    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 452
    Points : 24 863
    Points
    24 863
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    La documentation est dans les choux ! Peut ne pas devrait être ne peut pas et la définition des champs de classe me semble... bizarre (ou ma terminologie n'est pas la leurs)
    J'ai cette même impression aussi !
    Champ de classe c'est pour moi aussi class var
    Si l'on confronte Champs (Delphi) - Champs de classe et Déclaration des champs de classe, la documentation semble se contredire !

    J'ai fait un message sur la documentation pour avoir un éclaircissement au sujet de « champ d’instance » et « champ de classe »
    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

  17. #17
    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 430
    Points
    28 430
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    J'ai cette même impression aussi !
    Champ de classe c'est pour moi aussi class var
    Si l'on confronte Champs (Delphi) - Champs de classe et Déclaration des champs de classe, la documentation semble se contredire !

    J'ai fait un message sur la documentation pour avoir un éclaircissement au sujet de « champ d’instance » et « champ de classe »
    c'est de la traduction automatique
    "A helper type may not declare instance data, but class fields are allowed."

    ne peux pas déclarer de membre d'instance, mais il peut déclarer des membres de classe.

    c'est tout à fait logique puisqu'il est ici question de méthodes statiques (non dynamiques, à ne pas confondre avec les méthodes de classes en C++) qui peuvent donc manipuler l'instance mais certainement pas lui ajouter des membres. Par contre une membre de classe peut être ajouté, c'est juste une variable globale dont la visibilité est attachée à la classe.
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  18. #18
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    En testant XE4 j'ai vu que l'on pouvais écrire:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    ShowMessage(14.ToString);
    en fait dans SysUtils il y a:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
     TShortIntHelper = record helper for ShortInt
      (...)
      function ToString: string; overload; inline;
      (...)
     end;
    TStringHelper, TSingleHelper, TDoubleHelper...
    Sympa je trouve!
    Akim Merabet

  19. #19
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 452
    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 452
    Points : 24 863
    Points
    24 863
    Par défaut
    La Javaïsation du Delphi

    En C++Builder, c'est directement ShowMessage(14);
    Car ShowMessage attend un String et comme le constructor String(int) existe, cela fait la conversion implicitement


    Du coup si tu fais ton propre "record helper for ShortInt",
    est-ce que les deux cohabitent ?
    Cela répondra à ma question "le compilateur refuse-t-il deux class helper sur la même classe ?"
    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

  20. #20
    Membre averti Avatar de Moez.B
    Homme Profil pro
    Développeur Delphi
    Inscrit en
    Mars 2006
    Messages
    219
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : Tunisie

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

    Informations forums :
    Inscription : Mars 2006
    Messages : 219
    Points : 370
    Points
    370
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    La Javaïsation du Delphi

    En C++Builder, c'est directement ShowMessage(14);
    Car ShowMessage attend un String et comme le constructor String(int) existe, cela fait la conversion implicitement


    Du coup si tu fais ton propre "record helper for ShortInt",
    est-ce que les deux cohabitent ?
    Cela répondra à ma question "le compilateur refuse-t-il deux class helper sur la même classe ?"
    salut Shai,
    c'est marrant, c'est plutôt aussi la C-Sharpisation du Delphi car ToString() est une méthode de object dans C# ...
    Enfin, je crois que les class Helper peuvent assister à 'décorer' comme a demandé e-ric une classe ( merci Shai pour le coup des durs dans cette discussion à propos des design patterns http://www.developpez.net/forums/d13...tructeur-rtti/ ) car je comprend ce que c'est un décorateur maintenant
    Bye
    "L'homme supérieur est celui qui a une bienveillance égale pour tous, et qui est sans égoïsme et sans partialité." [Confucius]
    "Celui qui n'évolue pas disparaît." [Charles Darwin]
    “Without requirements or design, programming is the art of adding bugs to an empty text file.” [Louis Srygley]

Discussions similaires

  1. classe enregistrement audio
    Par cyriltec dans le forum C#
    Réponses: 2
    Dernier message: 30/03/2010, 09h52
  2. Réponses: 5
    Dernier message: 08/12/2004, 20h42
  3. Visibilité de methodes dans Classe de Class
    Par Math75 dans le forum C++
    Réponses: 9
    Dernier message: 28/09/2004, 12h48
  4. Réponses: 7
    Dernier message: 10/09/2004, 14h28
  5. pb constructeurs classes dérivant classe abstraite
    Par Cornell dans le forum Langage
    Réponses: 2
    Dernier message: 10/02/2003, 19h02

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