14 votes

Où se trouvent les exemples concrets d'attributs Delphi?

Je sais grâce à TMS Aurelius que nous pouvons utiliser la fonctionnalité d'attributs "nouveaux" de 2010 pour sérialiser les champs de table de base de données en propriétés d'objet à l'exécution, par exemple, et je ne suis pas un expert dans ce schéma orienté objet profond, donc je regarde le code source TMS et n'ai pas pu comprendre comment l'implémenter moi-même, pas pour la base de données, pas pour XML.

J'ai donc cherché tous les résultats de Google sur Attributs Delphi et toutes les personnes affichent des exemples de déclaration et s'arrêtent avant même de montrer leurs exemples en action.

Alors où sont les exemples réels de comment pouvons-nous projeter, déclarer, coder et UTILISER ces classes enrichies à l'intérieur d'un formulaire/code en cours d'exécution?

Quelqu'un a-t-il un exemple à partager ici ou connaît-il un bon article complet?

Édition1:

La réponse devrait avoir un TForm avec un TButton où, lorsque cliqué, exécute une utilisation des classes d'attributs créées, ne répondez pas en montrant seulement l'attribut et les interfaces de classes, car il y en a beaucoup de ces exemples de déclaration comme je l'ai dit auparavant

12voto

pf1957 Points 997

Je dois dire que ce n'est pas très clair pour moi quel genre d'exemple vous avez besoin. À mon avis, dans http://docwiki.embarcadero.com/RADStudio/Rio/en/Overview_of_Attributes vous devriez trouver tout ce dont vous avez besoin, à condition que vous ayez des connaissances de base en annotation et/ou en programmation d'aspects respective.

Un exemple dépend de la manière / du but pour lequel un auteur d'un logiciel particulier a utilisé des attributs. Vous avez mentionné le système ORM : l'utilisation typique ici est d'annoter un membre de la classe représentant une entité de base de données avec des informations supplémentaires nécessaires pour l'opération de la base de données dans le backend d'un tel framework. Supposons que vous ayez une entité de base de données ayant le champ SOCIÉTÉ CHAR(32) NOT NULL et que vous voulez le représenter dans une classe Delphi :

TSomeDBEntity = class(...)
  FCDS: TClientDataset;
  ...
  constructor Create;
  ... 
  [TCharColumn('SOCIÉTÉ', 32, false)]
  property NomSociete: string read GetNomSociete write SetNomSociete;
end;

alors vous définirez l'attribut TCharColumn avec un constructeur

constructor TCharColumn.Create(const AFieldName:string; ALength:integer; ANullable:boolean);
begin
  inherited;
  FName := AFieldName;
  FLength := ALength;
  FNullable := ANullable;
end;

Et l'utilisation d'une telle annotation pourrait ressembler à ceci :

FCDS := TClientDataset.Create(nil);
RttiContext := TRttiContext.Create;
try
  RttiType := RttiContext.GetType(self.ClassType);
  Props := RttiType.GetProperties;
  for Prop in Props do
    begin
      Attrs := Prop.GetAttributes;
      case Prop.PropertyType.TypeKind of
        tkUString:
          begin
            for Attr in Attrs do
              if Attr is TCharColumn then
              begin
                ColAttr := TCharColumn(Attr);
                FCDS.FieldDefs.Add(ColAttr.FName, ftString, ColAttr.FLength, not ColAttr.FNullable);
              end;
          end;
        else
          //... ;
      end;
    end;
finally
  RttiContext.Free;
end;

Ce morceau du programme montre comment définir des champs dans un ensemble de données en temps d'exécution en fonction d'une annotation en Delphi. Nous sommes limités en raison du manque de paramètres nommés, donc travailler avec une liste de paramètres n'est pas aussi flexible que cela devrait l'être par exemple comme en Java (comparez l'ensemble d'annotations TMS Aurelius http://www.tmssoftware.com/site/manuals/aurelius_manual.pdf et http://www.techferry.com/articles/hibernate-jpa-annotations.html

11voto

AlexSC Points 1235

Si vous souhaitez déclarer votre propre attribut, vous pouvez le faire comme ceci :

type
  TDisplayLabelAttribute = class(TCustomAttribute)
  private
    FText: string;
  public
    constructor Create(const aText: string);
    property Text: string read FText write FText;
  end;

Un attribut est une classe ordinaire, qui a TCustomAttribute comme son ancêtre. Vous l'implémentez comme d'habitude :

implementation

constructor TDisplayLabelAttribute.Create(const aText: string);
begin
  FText := aText;
end;

Maintenant que l'attribut est déclaré et implémenté, vous pouvez simplement l'utiliser :

[DisplayLabel('Ma Classe')]
TMyClass = class
end;

Donc maintenant vous avez un attribut déclaré et implémenté et vous l'avez utilisé pour ajouter une étiquette d'affichage à une classe. La phase finale consiste à utiliser cet attribut, car vous avez une classe décorée avec celui-ci. Le code qui utilise l'attribut ne réside ni dans l'attribut ni dans la classe décorée, il est implémenté dans la couche de service qui utilisera la décoration.

Disons que nous avons une classe qui retourne une éventuelle étiquette d'affichage pour une classe :

type
  TArtifactInspector = class
  public
    class function DisplayLabelFor(aClass: TClass): string;
  end;

Cette méthode inspectera une classe et renverra son étiquette d'affichage, si elle existe. Sinon, elle renverra une chaîne vide :

implementation

uses
  Rtti;

class function TArtifactInspector.DisplayLabelFor(aClass: TClass): string;
var
  rttiContext: TRttiContext;
  rttiType: TRttiType;
  attribute: TCustomAttribute;
begin
  rttiContext := TRttiContext.Create;
  try
    rttiType := rttiContext.GetType(aClass);
    for attribute in rttiType.GetAttributes do
      if attribute is TDisplayLabelAttribute then
        Exit(TDisplayLabelAttribute(attribute).Text);
    Result := '';
  finally
    rttiContext.Free;
  end; // try to recover and return the DisplayLabel
end;

9voto

binaryorganic Points 133

Je ne suis pas sûr si la question demande des exemples concrets d'utilisation d'attributs ou comment sérialiser des tables de base de données en objets en utilisant des attributs. L'exemple ci-dessous est un exemple simplifié (mais un exemple tout de même) montrant comment utiliser des attributs pour enregistrer les modifications apportées aux propriétés de l'objet.

Définissez votre attribut personnalisé

//Par convention, les attributs ne sont *pas* préfixés par un `T`
//et contiennent le mot `Attribute` dans leur nom
LoggableAttribute = class(TCustomAttribute)
  private
    FDescription : String;
  public
    constructor Create(Description: String);
    property Description: String read FDescription;
  end;

Le "hello world" des classes TProduct utilisant l'attribut

TProduct = Class(TObject)
   private
    FPrice: Double;
    FDescription: String;
    ..
   public  
    [LoggableAttribute('Prix du produit')]
    property Price : Double read FPrice write SetPrice;
    [Loggable('Description du produit')]   {la partie `Attribute` est facultative}
    property Description : String read FDescription write SetDescription;
    property IsDirty : Boolean read FIsDirty;
  End;

Toute classe possédant un "attribut loggable" peut être passée à cette méthode pour itérer à travers les propriétés et les enregistrer.

procedure LogChanges(LoggableClass: TObject);
var
 c : TRttiContext;
 t : TRttiType;
 p : TRttiProperty;
 a : TCustomAttribute;
 Value : TValue;
begin
 c := TRttiContext.Create;    
 try
   t := c.GetType(LoggableClass.ClassType);
   for p in t.getProperties do
     for a in p.GetAttributes do
       if a is TLoggableProperty then begin
         Value := p.GetValue(LoggableClass);   
         // enregistrer en base de données.. 
         AddLogEntry(p.Name, TLoggableProperty(a).Description, Value.ToString);
       end;
 finally
   c.Free;
 end;

end;

Exemple d'utilisation :

var
 P : TProduct;
begin    
 P := TProduct.Create; 
 P.LoadPropertiesFromDB;
 ...
 ... L'utilisateur modifie le prix ...    
 ... 
 P.Price := 499.99;
 ...
 ... Enregistrer le produit en base de données 
 if P.IsDirty then  // enregistrer et enregistrer l'activité
   LogChanges(P);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X