Где Delphi атрибуты реальных примеров мира?

Я знаю TMS Aurelius что мы можем использовать функцию" новые " атрибуты 2010 для сериализации полей таблицы базы данных в свойства объекта во время выполнения, например, и я не эксперт по этой глубокой объектно-ориентированной схеме, поэтому я смотрю в исходный код TMS и не могу понять, как реализовать его сам, не для БД, не для XML.

поэтому я искал все результаты Google на Delphi Attributes и все, что люди представляют декларации примеры, а затем останавливается перед даже показывая свои примеры в действии.

тогда где реальные примеры того, как мы можем проектировать, объявлять, кодировать и использовать эти сочные классы внутри формы/кода выполнения?

есть ли у кого-нибудь пример, чтобы поделиться здесь или знать хорошую статью, которая завершена?

Edit1:

ответ должен быть TForm С TButton где при нажатии выполнить некоторое использование созданных классов атрибутов, не отвечайте, показывая только атрибут и классы интерфейсы, потому что есть много из этих примеров объявления, как я сказал раньше

3 ответов


если вы хотите объявить свой собственный атрибут, вы можете сделать это следующим образом:

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

атрибут-это обычный класс, который имеет TCustomAttribute как его предок. Вы реализуете его как обычно:

implementation

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

теперь атрибут объявлен и реализован, вы можете просто использовать это:

[DisplayLabel('My Class')]
TMyClass = class
end;

Итак, теперь у вас есть атрибут, объявленный и реализованный, и вы использовали его для добавления метки отображения в некоторый класс. Заключительный этап-использовать это атрибут, так как у вас есть класс оформлен С ним. Код, который использует атрибут, не находится ни в атрибуте, ни в украшенном классе, он реализован в слое сервиса, который будет использовать украшение.

предположим, у нас есть класс, который возвращает возможную метку отображения для класса:

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

этот метод будет проверять класс и вернуть свою метку, учитывая, что он существует. В противном случае он возвращает пустую строку:

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;

Я должен сказать, что мне не очень ясно, какой пример вам нужен. ИМХО в http://docwiki.embarcadero.com/RADStudio/XE4/en/Overview_of_Attributes это все, что вам нужно, возможно, при условии, что у вас есть некоторые базовые знания аннотации и/или аспектного программирования.

пример зависит от способа/цели, для которой автор конкретного SW использовал атрибуты. Вы упомянули систему ORM: типичное использование здесь-аннотировать члена класса представление сущности БД с дополнительной информацией, необходимой для работы БД в бэкэнде такой структуры. Предположим, у вас есть объект DB, имеющий поле COMPANY CHAR (32) не NULL, и вы хотите представить его в классе Delphi:

TSomeDBEntity = class(...)
  FCDS: TClientDataset;
  ...
  constructor Create;
  ... 
  [TCharColumn('COMPANY', 32, false)]
  property CompanyName: string read GetCompanyName write SetCompanyName;
end;

затем вы определите атрибут TCharColumn с помощью конструктора

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

и использование такой аннотации может выглядеть так:

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;

этот фрагмент программы демонстрирует, как определить поля в набор данных во время выполнения на основе аннотации в Delphi. Мы ограничены немного из-за отсутствие именованных параметров, поэтому работать с списке параметр не является гибким, как должно быть, например как в Java (сравните ТМС Аврелий аннотация набор http://www.tmssoftware.com/site/manuals/aurelius_manual.pdf и http://www.techferry.com/articles/hibernate-jpa-annotations.html


не уверен, что вопрос задает реальные примеры использования атрибутов или как сериализовать таблицы БД в объекты с использованием атрибутов. Приведенный ниже пример-надуманный простой (но тем не менее пример), показывающий, как использовать атрибуты для регистрации изменений свойств объекта.

определите свой пользовательский атрибут

//By convention attributes are *not* prefixed with a `T` 
//and have the word `Attribute` in their name
LoggableAttribute = class(TCustomAttribute)
  private
    FDescription : String;
  public
    constructor Create(Description: String);
    property Description: String read FDescription;
  end;

"hello world" классов TProduct с помощью атрибута

TProduct = Class(TObject)
   private
    FPrice: Double;
    FDescription: String;
    ..
   public  
    [LoggableAttribute('Product Price')]
    property Price : Double read FPrice write SetPrice;
    [Loggable('Product Description')]   {the `Attribute` part is optional}
    property Description : String read FDescription write SetDescription;
    property IsDirty : Boolean read FIsDirty;
  End;

любой класс, который имеет "loggable атрибут" может быть передан этому методу, чтобы перебирать свойства и регистрировать их.

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);   
         // log to db.. 
         AddLogEntry(p.Name, TLoggableProperty(a).Description, Value.ToString);
       end;
 finally
   c.Free;
 end;

конец;

пример использования:

var
 P : TProduct;
begin    
 P := TProduct.Create; 
 P.LoadPropertiesFromDB;
 ...
 ... User edits price ...    
 ... 
 P.Price := 499.99;
 ...
 ... Save product to DB 
 if P.IsDirty then  // save and log
   LogChanges(P);