Sign in Join
Wiki copytemporary

Custom Attributes/ru: what changed

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

OldNewLine
1-Пользовательские атрибуты в настоящее время позволяют украшать определения типов и published свойства классов дополнительными метаданными, которые можно запрашивать с помощью RTTI (информация о типе времени выполнения).
1+Пользовательские атрибуты в настоящее время позволяют украшать определения типов и published свойства классов дополнительными метаданными, которые можно запрашивать с помощью RTTI (информация о типе времени выполнения).
22
3-> **Note:** В настоящее время (по состоянию на октябрь 2020 г.) эта функция доступна только в транке FPC (также известной как 3.3.1).
3+[![Note-icon.png](/wiki-images/b/be/Note-icon.png)](</File:Note-icon.png>)
44
5-\
5+**Примечание:** В настоящее время (по состоянию на октябрь 2020 г.) эта функция доступна только в транке FPC (также известной как 3.3.1).
66
7+
8+
9+## Contents
10+
11+ * 1 Для чего можно использовать атрибуты?
12+ * 2 Как объявляются атрибуты?
13+ * 3 Как используются атрибуты?
14+ * 3.1 Запрос атрибутов
15+ * 4 Совместимость функций атрибутов с Delphi
16+ * 5 Полный пример
17+ * 6 См.также
18+
719## Для чего можно использовать атрибуты?
820
9-Атрибут используется для связывания определенных метаданных с классом. Например, вы можете использовать атрибут, чтобы пометить класс именем соответствующей таблицы базы данных или аннотировать класс веб-службы строкой, определяющей его базовый путь.
21+Атрибут используется для связывания определенных метаданных с классом. Например, вы можете использовать атрибут, чтобы пометить класс именем соответствующей таблицы базы данных или аннотировать класс веб-службы строкой, определяющей его базовый путь.
1022
1123## Как объявляются атрибуты?
1224
13-Атрибуты — это просто классы, происходящие от нового системного типа `TCustomAttribute`. Конструкторы таких потомков `TCustomAttribute` являются наиболее важной функцией для реализации, поскольку они используются для передачи дополнительных параметров атрибуту (таких, как имя связанной таблицы базы данных или базовый путь в приведенных выше примерах).
25+Атрибуты — это просто классы, происходящие от нового системного типа `TCustomAttribute`. Конструкторы таких потомков `TCustomAttribute` являются наиболее важной функцией для реализации, поскольку они используются для передачи дополнительных параметров атрибуту (таких, как имя связанной таблицы базы данных или базовый путь в приведенных выше примерах).
1426
15-**Важно**: если вы хотите использовать свой тип атрибута без каких-либо аргументов, вы *должны* самостоятельно объявить конструктор без параметров, поскольку один из `TCustomAttribute` является закрытым (private).
27+**Важно** : если вы хотите использовать свой тип атрибута без каких-либо аргументов, вы _должны_ самостоятельно объявить конструктор без параметров, поскольку один из `TCustomAttribute` является закрытым (private).
1628
1729## Как используются атрибуты?
1830
19-Атрибуты привязываются к типу или свойству путем указания хотя бы одного предложения атрибута перед типом или свойством. Для типа атрибут указывается в определении типа (например, в объявлении класса, записи или перечисления) или в повторном объявлении уникального типа (например, `TLongInt = type LongInt`). Простое переименование типов (например, `TLongInt = LongInt`) не допускается.
20-
21-Предложения атрибутов доступны только в том случае, если установлен новый переключатель режимов `PREFIXEDATTRIBUTES`, который используется по умолчанию в режимах Delphi и DelphiUnicode.
31+Атрибуты привязываются к типу или свойству путем указания хотя бы одного предложения атрибута перед типом или свойством. Для типа атрибут указывается в определении типа (например, в объявлении класса, записи или перечисления) или в повторном объявлении уникального типа (например, `TLongInt = type LongInt`). Простое переименование типов (например, `TLongInt = LongInt`) не допускается.
2232
23-Синтаксис предложения атрибута следующий:
33+Предложения атрибутов доступны только в том случае, если установлен новый переключатель режимов `PREFIXEDATTRIBUTES`, который используется по умолчанию в режимах Delphi и DelphiUnicode.
2434
25-``` pascal
26- ATTRIBUTECLAUSE::='[' ATTRIBUTELIST ']'
27- ATTRIBUTELIST::=ATTRIBUTE [, ATTRIBUTELIST ]
28- ATTRIBUTE::=IDENTIFIER [ ( PARAMLIST ) ]
29- PARAMLIST::=CONSTEXPR [, PARAMLIST ]
35+Синтаксис предложения атрибута следующий:
3036```
31-
32-*IDENTIFIER* — это имя класса атрибута. Если вы называете класс атрибута заканчивающимся на "Attribute" (случай суффикса "Attribute" не имеет значения), то имя может использоваться впоследствии без суффикса "Attribute". Таким образом, `TMyAttribute` и `TMy` являются эквивалентными альтернативами в следующем примере:
33-
34-```delphi
37+ATTRIBUTECLAUSE::='[' ATTRIBUTELIST ']'
38+ ATTRIBUTELIST::=ATTRIBUTE [, ATTRIBUTELIST ]
39+ ATTRIBUTE::=IDENTIFIER [ ( PARAMLIST ) ]
40+ PARAMLIST::=CONSTEXPR [, PARAMLIST ]
41+```
3542
43+_IDENTIFIER_ — это имя класса атрибута. Если вы называете класс атрибута заканчивающимся на "Attribute" (случай суффикса "Attribute" не имеет значения), то имя может использоваться впоследствии без суффикса "Attribute". Таким образом, `TMyAttribute` и `TMy` являются эквивалентными альтернативами в следующем примере:
44+```
3645program 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.
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.
8998```
9099
91100### Запрос атрибутов
92101
93-Атрибуты могут быть доступны как модулю `TypInfo`, так и модулю `Rtti`.
102+Атрибуты могут быть доступны как модулю `TypInfo`, так и модулю `Rtti`.
94103
95-Для модуля `TypInfo` доступны следующие способы доступа к атрибутам:
104+Для модуля `TypInfo` доступны следующие способы доступа к атрибутам:
96105
97-Для типов:
106+Для типов:
98107
99-- используйте поле `AttributesTable` в `TTypeData`
100-- использовать `GetAttributeTable` для `PTypeInfo`
101-- используйте `GetAttribute` в таблице атрибутов вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
108+ * используйте поле `AttributesTable` в `TTypeData`
109+ * использовать `GetAttributeTable` для `PTypeInfo`
110+ * используйте `GetAttribute` в таблице атрибутов вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
102111
103-Для свойств:
112+Для свойств:
104113
105-- используйте `AttributesTable` из `TPropInfo`
106-- используйте `GetAttribute` в таблице атрибутов вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
107-- используйте `GetPropAttribute` в `PPropInfo` вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
114+ * используйте `AttributesTable` из `TPropInfo`
115+ * используйте `GetAttribute` в таблице атрибутов вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
116+ * используйте `GetPropAttribute` в `PPropInfo` вместе с индексом, чтобы получить экземпляр `TCustomAttribute`
108117
109-Для модуля `Rtti` доступны следующие способы доступа к атрибутам:
118+Для модуля `Rtti` доступны следующие способы доступа к атрибутам:
110119
111-Для типов:
120+Для типов:
112121
113-- используйте `GetAttributes` для `TRttiType` рассматриваемого типа
122+ * используйте `GetAttributes` для `TRttiType` рассматриваемого типа
114123
115-Для свойств:
124+Для свойств:
116125
117-- используйте `GetAttributes` для `TRttiProperty` рассматриваемого свойства
126+ * используйте `GetAttributes` для `TRttiProperty` рассматриваемого свойства
118127
119128## Совместимость функций атрибутов с Delphi
120129
121-Сама функция совместима с Delphi при условии, что FPC гораздо более неумолим в отношении несвязанных свойств. Если класс атрибута неизвестен или предложения атрибута не связаны с допустимым типом или свойством, компилятор выдаст ошибку.
122-
123-RTTI от FPC не считается совместимым с Delphi. Однако он охватывает ту же функциональность. В отличие от Delphi (который использует Invoke для создания экземпляра атрибута), FPC использует функцию конструктора. Преимущество реализации FPC заключается в том, что она работает на системах, которые не имеют полной поддержки Invoke.
130+Сама функция совместима с Delphi при условии, что FPC гораздо более неумолим в отношении несвязанных свойств. Если класс атрибута неизвестен или предложения атрибута не связаны с допустимым типом или свойством, компилятор выдаст ошибку.
124131
125-Кроме того, использование переключателя режима *PREFIXEDATTRIBUTES* отключает разделы директив для функций, методов и типов процедур/методов.
132+RTTI от FPC не считается совместимым с Delphi. Однако он охватывает ту же функциональность. В отличие от Delphi (который использует Invoke для создания экземпляра атрибута), FPC использует функцию конструктора. Преимущество реализации FPC заключается в том, что она работает на системах, которые не имеют полной поддержки Invoke.
126133
127-Следующее больше не разрешено при включенном переключателе режимов *PREFIXEDATTRIBUTES*:
134+Кроме того, использование переключателя режима _PREFIXEDATTRIBUTES_ отключает разделы директив для функций, методов и типов процедур/методов.
128135
129-```delphi
136+Следующее больше не разрешено при включенном переключателе режимов _PREFIXEDATTRIBUTES_ :
137+```
130138procedure Test; [cdecl];
131-begin
132-end;
139+ begin
140+ end;
133141```
134142
135143## Полный пример
136-
137-```Delphi
144+```
138145program 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;
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;
218175 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.
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;
229+ 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.
235242```
236243
237244## См.также
238245
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 по атрибутам свойств
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 по атрибутам свойств
242249
243250---
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
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).*

Back to history