Sign in Join
Wiki copytemporary

Custom Attributes/ru: what changed

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

Title: Custom Attributes/ru

OldNewLine
1+Пользовательские атрибуты в настоящее время позволяют украшать определения типов и published свойства классов дополнительными метаданными, которые можно запрашивать с помощью RTTI (информация о типе времени выполнения).
2+
3+> **Note:** В настоящее время (по состоянию на октябрь 2020 г.) эта функция доступна только в транке FPC (также известной как 3.3.1).
4+
5+\
6+
7+## Для чего можно использовать атрибуты?
8+
9+Атрибут используется для связывания определенных метаданных с классом. Например, вы можете использовать атрибут, чтобы пометить класс именем соответствующей таблицы базы данных или аннотировать класс веб-службы строкой, определяющей его базовый путь.
10+
11+## Как объявляются атрибуты?
12+
13+Атрибуты — это просто классы, происходящие от нового системного типа `TCustomAttribute`. Конструкторы таких потомков `TCustomAttribute` являются наиболее важной функцией для реализации, поскольку они используются для передачи дополнительных параметров атрибуту (таких, как имя связанной таблицы базы данных или базовый путь в приведенных выше примерах).
14+
15+**Важно**: если вы хотите использовать свой тип атрибута без каких-либо аргументов, вы *должны* самостоятельно объявить конструктор без параметров, поскольку один из `TCustomAttribute` является закрытым (private).
16+
17+## Как используются атрибуты?
18+
19+Атрибуты привязываются к типу или свойству путем указания хотя бы одного предложения атрибута перед типом или свойством. Для типа атрибут указывается в определении типа (например, в объявлении класса, записи или перечисления) или в повторном объявлении уникального типа (например, `TLongInt = type LongInt`). Простое переименование типов (например, `TLongInt = LongInt`) не допускается.
20+
21+Предложения атрибутов доступны только в том случае, если установлен новый переключатель режимов `PREFIXEDATTRIBUTES`, который используется по умолчанию в режимах Delphi и DelphiUnicode.
22+
23+Синтаксис предложения атрибута следующий:
24+
25+``` pascal
26+ ATTRIBUTECLAUSE::='[' ATTRIBUTELIST ']'
27+ ATTRIBUTELIST::=ATTRIBUTE [, ATTRIBUTELIST ]
28+ ATTRIBUTE::=IDENTIFIER [ ( PARAMLIST ) ]
29+ PARAMLIST::=CONSTEXPR [, PARAMLIST ]
30+```
31+
32+*IDENTIFIER* — это имя класса атрибута. Если вы называете класс атрибута заканчивающимся на "Attribute" (случай суффикса "Attribute" не имеет значения), то имя может использоваться впоследствии без суффикса "Attribute". Таким образом, `TMyAttribute` и `TMy` являются эквивалентными альтернативами в следующем примере:
33+
34+```delphi
35+
36+program tcustomattr;
37+
38+{$mode objfpc}{$H+}
39+{$modeswitch prefixedattributes}
40+
41+type
42+ TMyAttribute = class(TCustomAttribute)
43+ constructor Create;
44+ constructor Create(aArg: String);
45+ constructor Create(aArg: TGUID);
46+ constructor Create(aArg: LongInt);
47+ end;
48+
49+ {$M+}
50+ [TMyAttribute]
51+ TTestClass = class
52+ private
53+ fTest: LongInt;
54+ published
55+ [TMyAttribute('Test')]
56+ property Test: LongInt read fTest;
57+ end;
58+ {$M-}
59+
60+ [TMyAttribute(1234)]
61+ [TMy('Hello World')]
62+ TTestEnum = (
63+ teOne,
64+ teTwo
65+ );
66+
67+ [TMyAttribute(IInterface), TMy(42)]
68+ TLongInt = type LongInt;
69+
70+constructor TMyAttribute.Create;
71+begin
72+end;
73+
74+constructor TMyAttribute.Create(aArg: String);
75+begin
76+end;
77+
78+constructor TMyAttribute.Create(aArg: LongInt);
79+begin
80+end;
81+
82+constructor TMyAttribute.Create(aArg: TGUID);
83+begin
84+end;
85+
86+begin
87+
88+end.
89+```
90+
91+### Запрос атрибутов
92+
93+Атрибуты могут быть доступны как модулю `TypInfo`, так и модулю `Rtti`.
94+
95+Для модуля `TypInfo` доступны следующие способы доступа к атрибутам:
96+
97+Для типов:
98+
99+- используйте поле `AttributesTable` в `TTypeData`
100+- использовать `GetAttributeTable` для `PTypeInfo`
101+- используйте `GetAttribute` в таблице атрибутов вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
102+
103+Для свойств:
104+
105+- используйте `AttributesTable` из `TPropInfo`
106+- используйте `GetAttribute` в таблице атрибутов вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
107+- используйте `GetPropAttribute` в `PPropInfo` вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
108+
109+Для модуля `Rtti` доступны следующие способы доступа к атрибутам:
110+
111+Для типов:
112+
113+- используйте `GetAttributes` для `TRttiType` рассматриваемого типа
114+
115+Для свойств:
116+
117+- используйте `GetAttributes` для `TRttiProperty` рассматриваемого свойства
118+
119+## Совместимость функций атрибутов с Delphi
120+
121+Сама функция совместима с Delphi при условии, что FPC гораздо более неумолим в отношении несвязанных свойств. Если класс атрибута неизвестен или предложения атрибута не связаны с допустимым типом или свойством, компилятор выдаст ошибку.
122+
123+RTTI от FPC не считается совместимым с Delphi. Однако он охватывает ту же функциональность. В отличие от Delphi (который использует Invoke для создания экземпляра атрибута), FPC использует функцию конструктора. Преимущество реализации FPC заключается в том, что она работает на системах, которые не имеют полной поддержки Invoke.
124+
125+Кроме того, использование переключателя режима *PREFIXEDATTRIBUTES* отключает разделы директив для функций, методов и типов процедур/методов.
126+
127+Следующее больше не разрешено при включенном переключателе режимов *PREFIXEDATTRIBUTES*:
128+
129+```delphi
130+procedure Test; [cdecl];
131+begin
132+end;
133+```
134+
135+## Полный пример
136+
137+```Delphi
138+program testattributes;
139+{
140+ Это простой пример использования настраиваемых атрибутов.
141+ Класс использует настраиваемый атрибут для получения статической даты.
142+ при запуске программы. Это только для демонстрации.
143+ Это демо:
144+ - создает
145+ - украшает
146+ - возвращает
147+}
148+
149+{$mode delphi}{$H+}{$M+}
150+{$warn 5079 off} { отключаем экспериментальное предупреждение }
151+uses
152+ sysutils, typinfo, rtti, classes;
153+
154+type
155+ {Пользовательский атрибут для украшения класса с определенной датой }
156+ ADateTimeAttribute = class(TCustomAttribute)
157+ private
158+ FArg:TDateTime;
159+ public
160+ { Просто чтобы показать, что пользовательский атрибут может иметь несколько конструкторов }
161+ constructor Create(const aArg: TDateTime);overload;
162+ { Мы можем использовать предопределенное включение компилятора %DATE%
163+ В контексте пользовательского атрибута нам нужно
164+ постоянное выражение для параметра по умолчанию}
165+ constructor Create(const aArg: String = {$I %DATE%});overload;
166+ published
167+ property Date:TDateTime read Farg;
168+ end;
169+
170+ { Класс datetime, украшенный нашим пользовательским атрибутом }
171+ { Обратите внимание, что вы можете не указывать 'Attribute', компилятор разрешает это. }
172+ { [ADateTime(21237.0)] использует первый конструктор, отображая дату в 1958 году }
173+
174+ {Это вызывает второй конструктор }
175+ [ADateTime]
176+ TMyDateTimeClass = class
177+ private
178+ FDateTime:TDateTime;
179+ public
180+ constructor create;
181+ published
182+ [ADateTime]
183+ property Day:TDateTime read FDatetime write FdateTime;
184+ end;
185+
186+ constructor ADateTimeAttribute.Create(const aArg: TDateTime);
187+ begin
188+ FArg := aArg;
189+ end;
190+
191+ constructor ADateTimeAttribute.Create(const aArg: string );
192+ var
193+ MySettings:Tformatsettings;
194+ begin
195+ { настраиваем формат даты в соответствии с тем, как
196+ задан включенный формат компилятора %DATE% }
197+ MySettings :=DefaultFormatSettings;
198+ MySettings.ShortDateFormat:='yyyymmdd';
199+ MySettings.DateSeparator :='/';
200+ { Теперь конвертируем }
201+ FArg := StrToDateTime(aArg, MySettings);
202+ end;
203+
204+ { Мы запрашиваем rtti, чтобы задать значение }
205+ constructor TMyDateTimeClass.Create;
206+ var
207+ Context : TRttiContext;
208+ AType : TRttiType;
209+ Attribute : TCustomAttribute;
210+ begin
211+ inherited;
212+ Context := TRttiContext.Create;
213+ try
214+ AType := Context.GetType(typeinfo(TMyDateTimeClass));
215+ for Attribute in AType.GetAttributes do begin
216+ if Attribute is ADateTimeAttribute then
217+ FDateTime := ADateTimeAttribute(Attribute).Date;
218+ end;
219+ finally
220+ Context.Free
221+ end;
222+ end;
223+
224+
225+var
226+ Test:TMyDateTimeClass;
227+begin
228+ Test := TMyDateTimeClass.Create;
229+ try
230+ writeln('Дата компиляции :',DateTimeToStr(Test.Day));
231+ finally
232+ test.free;
233+ end;
234+end.
235+```
236+
237+## См.также
238+
239+- [[FPC New Features Trunk]]
240+- <http://docwiki.embarcadero.com/RADStudio/XE6/en/Overview_of_Attributes> - Справочник по атрибутам Delphi
241+- <http://delphi.about.com/od/oopindelphi/a/delphi-attributes-understanding-using-attributes-in-delphi.htm> Учебник Delphi по атрибутам свойств
242+
243+---
244+*From the Free Pascal wiki, page "Custom Attributes/ru", as it stood on 2022-12-30 after a change by Zoltanleo, out of the wiki's dump of 2024-05-26. 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).*
245+Category: FPC

Back to history