我知道TMS Aurelius我们可以使用“new”2010属性功能在运行时将数据库表字段序列化为对象属性,例如,我不是这个深层面向对象模式的专家,所以我查看了TMS源代码,无法理解如何自己实现它,不是为了DB,而是为了XML。
所以我在Delphi Attributes
上查找了所有Google的搜索结果,所有人发布的都是声明示例,然后在展示他们的示例之前就停止了。
那么我们如何在表单/执行代码中投射,声明,编码和使用那些juiced类的真实世界示例在哪里?
有没有人可以在这里分享一个例子,或者知道一篇完整的好文章?
EDIT1:
答案应该有TForm
TButton
,当点击时,执行一些使用创建的属性类,不回答只显示属性和类接口,因为有很多我之前讲过的那些宣言示例
答案 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;
然后您将使用构造函数
定义属性TCharColumnconstructor 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.pdf和http://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;