Sign in Join
Wiki copytemporary

Custom Attributes/ru: what changed

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

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

Back to history