Delphi属性真实世界的例子在哪里?

时间:2013-07-27 13:14:11

标签: delphi oop attributes rtti

我知道TMS Aurelius我们可以使用“new”2010属性功能在运行时将数据库表字段序列化为对象属性,例如,我不是这个深层面向对象模式的专家,所以我查看了TMS源代码,无法理解如何自己实现它,不是为了DB,而是为了XML。

所以我在Delphi Attributes上查找了所有Google的搜索结果,所有人发布的都是声明示例,然后在展示他们的示例之前就停止了。

那么我们如何在表单/执行代码中投射,声明,编码和使用那些juiced类的真实世界示例在哪里?

有没有人可以在这里分享一个例子,或者知道一篇完整的好文章?

EDIT1:

答案应该有TForm TButton,当点击时,执行一些使用创建的属性类,不回答只显示属性和类接口,因为有很多我之前讲过的那些宣言示例

3 个答案:

答案 0 :(得分:10)

我必须说我不太清楚你需要什么样的例子。 http://docwiki.embarcadero.com/RADStudio/XE4/en/Overview_of_Attributes中的恕我直言是您应该需要的一切,或许可以提供您对注释和/或方面编程的一些基本知识。

示例取决于特定SW的作者使用属性的方式/目的。您提到了ORM系统:这里的典型用法是注释表示数据库实体的类的成员,并在此类框架的后端为DB操作提供必要的附加信息。假设您有一个DB实体,其字段为COMPANY CHAR(32)NOT 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中一样(比较TMS Aurelius注释集http://www.tmssoftware.com/site/manuals/aurelius_manual.pdfhttp://www.techferry.com/articles/hibernate-jpa-annotations.html

答案 1 :(得分:8)

不确定问题是否要求使用属性的真实世界示例或如何使用属性将db表序列化为对象。下面的例子是一个人为的简单例子(但不过是一个例子),展示了如何使用属性来记录对象属性的更改。

定义自定义属性

//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;

使用属性

的类TProduct的“hello world”
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);

答案 2 :(得分:8)

如果您想声明自己的属性,可以这样做:

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;