Sign in Join
Wiki copytemporary

Custom Attributes/zh CN: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
11自定义属性(Custom Attributes)目前允许您为类型定义和类的已发布属性添加额外的元数据,这些元数据可以通过RTTI(运行时类型信息)进行查询。
22
33**截至2020年10月,该功能仅在FPC主干版本(即3.3.1)中可用**
44
55## Contents
66
77 * 1 属性可以用来做什么?
88 * 2 如何声明属性?
99 * 3 如何使用属性?
1010 * 3.1 查询属性
1111 * 4 属性特性与Delphi的兼容性
1212 * 5 完整示例
1313
1414## 属性可以用来做什么?
1515
1616属性用于将特定的元数据与类相关联。例如,您可以使用属性来标记一个类,指定其对应的数据库表名,或者为Web服务类添加一个标识其基本路径的字符串。
1717
1818## 如何声明属性?
1919
2020属性只是从新的系统类型`TCustomAttribute`派生的类。实现此类`TCustomAttribute`后代的构造函数是最重要的特性,因为它们用于向属性传递额外的参数(如上述示例中的关联数据库表名或基本路径)。
2121
2222**重要** :如果您想在不使用任何参数的情况下使用您的属性类型,则必须自己声明一个无参数的构造函数,因为`TCustomAttribute`的构造函数是私有的。
2323
2424## 如何使用属性?
2525
2626通过将至少一个属性子句放在类型或属性之前,可以将属性绑定到类型或属性。对于类型,属性在类型定义(如类、记录或枚举声明)或唯一类型重声明(例如"TLongInt = type LongInt")中指定。仅允许类型重声明,不允许仅重命名类型(例如"TLongInt = LongInt")。
2727
2828如果设置了新的模式开关`PREFIXEDATTRIBUTES`(在Delphi和DelphiUnicode模式下是默认的),则可用属性子句。
2929
3030属性子句的语法如下:
3131```
3232ATTRIBUTECLAUSE::='[' ATTRIBUTELIST ']'
3333 ATTRIBUTELIST::=ATTRIBUTE [, ATTRIBUTELIST ]
3434 ATTRIBUTE::=IDENTIFIER [ ( PARAMLIST ) ]
3535 PARAMLIST::=CONSTEXPR [, PARAMLIST ]
3636```
3737
3838其中,`IDENTIFIER`是属性类的名称。如果属性类的名称以"Attribute"结尾(不区分大小写),则后续可以省略"Attribute"后缀。因此,在以下示例中,`TMyAttribute`和`TMy`是等效的替代方案:
3939```
4040program tcustomattr;
4141
4242 {$mode objfpc}{$H+}$
4343 {$modeswitch prefixedattributes}
4444
4545 type
4646 TMyAttribute = class(TCustomAttribute)
4747 constructor Create;
4848 constructor Create(aArg: String);
4949 constructor Create(aArg: TGUID);
5050 constructor Create(aArg: LongInt);
5151 end;
5252
5353 {$M+}
5454 [TMyAttribute]
5555 TTestClass = class
5656 private
5757 fTest: LongInt;
5858 published
5959 [TMyAttribute('Test')]
6060 property Test: LongInt read fTest;
6161 end;
6262 {$M-}
6363
6464 [TMyAttribute(1234)]
6565 [TMy('Hello World')]
6666 TTestEnum = (
6767 teOne,
6868 teTwo
6969 );
7070
7171 [TMyAttribute(IInterface), TMy(42)]
7272 TLongInt = type LongInt;
7373
7474 constructor TMyAttribute.Create;
7575 begin
7676 end;
7777
7878 // ... 其他构造函数实现 ...
7979
8080 constructor TMyAttribute.Create(aArg: String);
8181 begin
8282 end;
8383
8484 constructor TMyAttribute.Create(aArg: LongInt);
8585 begin
8686 end;
8787
8888 constructor TMyAttribute.Create(aArg: TGUID);
8989 begin
9090 end;
9191
9292 begin
9393
9494
9595 begin
9696
9797 end.
9898```
9999
100100### 查询属性
101101
102102属性可以通过TypInfo和Rtti单元进行访问。
103103
104104对于TypInfo单元,访问属性的方式如下:
105105
106106对于类型:
107107
108108 * 使用`TTypeData`中的`AttributesTable`字段、
109109 * 对`PTypeInfo`使用`GetAttributeTable`、
110110 * 对属性表使用`GetAttribute`结合索引获取`TCustomAttribute`实例。
111111
112112对于属性:
113113
114114 * 使用`TPropInfo`的`AttributesTable`、
115115 * 对属性表使用`GetAttribute`结合索引获取`TCustomAttribute`实例、
116116 * 对`PPropInfo`使用`GetPropAttribute`结合索引获取`TCustomAttribute`实例。
117117
118118对于Rtti单元,访问属性的方式如下:
119119
120120对于类型:
121121
122122 * 对目标类型的`TRttiType`使用`GetAttributes`。
123123
124124对于属性:
125125
126126 * 对目标属性的`TRttiProperty`使用`GetAttributes`。
127127
128128## 属性特性与Delphi的兼容性
129129
130130该特性本身与Delphi兼容,但FPC对未绑定属性的容忍度较低。如果属性类未知或属性子句未绑定到有效的类型或属性,编译器将生成错误。
131131
132132FPC的RTTI不被认为是与Delphi兼容的,但它涵盖了相同的功能。与Delphi(使用Invoke创建属性实例)不同,FPC使用构造函数函数。FPC的实现优势在于它可以在没有完整Invoke支持的系统上工作。
133133
134134此外,使用`PREFIXEDATTRIBUTES`模式开关会禁用函数、方法和过程/方法类型的指令子句。启用`PREFIXEDATTRIBUTES`模式开关后,以下用法不再允许:
135135```
136136procedure Test; [cdecl];
137137 begin
138138
139139 end;
140140```
141141
142142## 完整示例
143143```
144144program testattributes;
145145 {
146146 这是一个简单的示例,说明如何使用自定义属性。
147147 该类使用自定义属性在程序启动时检索静态日期。这仅用于演示。
148148 此演示包含:
149149 - 创建
150150 - 装饰
151151 - 检索
152152 }
153153
154154 {$mode delphi}{$H+}{$M+}
155155 {$warn 5079 off} { 关闭实验性警告 }
156156 uses
157157 sysutils, typinfo, rtti, classes;
158158
159159 type
160160 { 用于装饰类以指定特定日期的自定义属性 }
161161 ADateTimeAttribute = class(TCustomAttribute)
162162 private
163163 FArg:TDateTime;
164164 public
165165 { 展示自定义属性可以有多个构造函数 }
166166 constructor Create(const aArg: TDateTime);overload;
167167 { 我们可以使用预定义的%DATE%编译器包含
168168 在自定义属性的上下文中,我们需要一个
169169 常量表达式作为默认参数 }
170170 constructor Create(const aArg: String = {$I %DATE%});overload;
171171 published
172172 property Date:TDateTime read FArg;
173173 end;
174174
175175 { 使用我们的自定义属性装饰的日期时间类 }
176176 { 注意:您可以省略'Attribute',编译器会解析它 }
177177 { [ADateTime(21237.0)] 调用第一个构造函数,显示1958年的某个日期 }
178178
179179 { 这将调用第二个构造函数 }
180180 [ADateTime]
181181 TMyDateTimeClass = class
182182 private
183183 FDateTime:TDateTime;
184184 public
185185 constructor create;
186186 published
187187 [ADateTime]
188188 property Day:TDateTime read FDateTime write FDateTime;
189189 end;
190190
191191 constructor ADateTimeAttribute.Create(const aArg: TDateTime);
192192 begin
193193 FArg := aArg;
194194 end;
195195
196196 constructor ADateTimeAttribute.Create(const aArg: string );
197197 var
198198 MySettings:TFormatSettings;
199199 begin
200200 { 根据编译器如何格式化%DATE%包含来设置日期格式 }
201201 MySettings := DefaultFormatSettings;
202202 MySettings.ShortDateFormat:='yyyymmdd';
203203 MySettings.DateSeparator :='/';
204204 { 现在进行转换 }
205205 FArg := StrToDateTime(aArg, MySettings);
206206 end;
207207
208208 { 我们查询rtti来设置值 }
209209 constructor TMyDateTimeClass.Create;
210210 var
211211 Context : TRttiContext;
212212 AType : TRttiType;
213213 Attribute : TCustomAttribute;
214214 begin
215215 inherited;
216216 Context := TRttiContext.Create;
217217 try
218218 AType := Context.GetType(TypeInfo(TMyDateTimeClass));
219219 for Attribute in AType.GetAttributes do begin
220220 if Attribute is ADateTimeAttribute then
221221 FDateTime := ADateTimeAttribute(Attribute).Date;
222222 end;
223223 finally
224224 Context.Free
225225 end;
226226 end;
227227
228228 var
229229 Test:TMyDateTimeClass;
230230 begin
231231 Test := TMyDateTimeClass.Create;
232232 try
233233 writeln('Compile date is :',DateTimeToStr(Test.Day));
234234 finally
235235 Test.Free;
236236 end;
237237 end.
238238```
239239
240240---
241-*From the Free Pascal wiki, page "Custom Attributes/zh CN", as the Internet Archive kept it on 2025-05-16. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
241+*From the Free Pascal wiki, page "Custom Attributes/zh CN", as the Internet Archive kept it on 2025-05-16, last changed on 2024-07-13. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history