![]() |
Использование атрибутов и наследников TCustomAttribute в Delphi 2010Источник: delphi2010 Александр Божко
В Delphi 2010 атрибуты были добавлены как функциональность языка. Они были доступны в Delphi Prism (для .Net) и вот теперь схожая функциональность появилась и для Win32. // Объявление атрибута
TAttrTest = class(TCustomAttribute)
end;
// Место, где вы можете использовать атрибуты
[TAttrTest]
TRec = Record
[TAttrTest]
value : String;
[TAttrTest]
procedure DoThis([TAttrTest]arg1: String);
End;
[TAttrTest]
TMyEnum = (enOne,enTwo,enThree);
[TAttrTest]
TMySet = set of TMyEnum;
[TAttrTest]
TObj = class(TObject)
private
[TAttrTest]
FID: Integer;
public
[TAttrTest]
FName : String;
[TAttrTest]
property Id : Integer read FID write FID;
[TAttrTest]
constructor Create;
[TAttrTest]
destructor Destroy; override;
[TAttrTest]
procedure DoThis;
end;
var
[TAttrTest]
I : Integer;
Так как же работают атрибуты в Delphi 2010? {Базовый класс для всех пользовательских атрибутов. Экземпляры атрибутов создаются RTTI модулем,
и являются собственностью тех членов, к которым они применяются}
TCustomAttribute = class(TObject)
end;
Задавать только имя для нового атрибута имеет смысл лишь в редких случаях, обычно вам нужно привязать какие-то данные. Это делается посредством конструктора. Следующий пример показывает, как сделать вызов конструктора в атрибуте. Type
TAttrTest2 = class(TObject)
private
FId : Integer;
public
constructor Create(aID : Integer);
property ID : Integer read FID write FID;
end;
[TAttrTest2(123)]
TMyObject = Class(TObject)
end;
Это сделано исключительно для того, что бы объявить Атрибут и "украсить" им ваш тип. Доступ к значению атрибутов осуществляется с помощью rtti.pas, общие основы того как это работает я описал в предыдущем посте. Следующий код показывает, как осуществлять доступ к атрибутам. program Project10;
{$APPTYPE CONSOLE}
uses
SysUtils, RTTI;
type
TAttrTest2 = class(TCustomAttribute)
private
FId : Integer;
public
constructor Create(aID : Integer);
property ID : Integer read FID write FID;
end;
[TAttrTest2(1)]
[TAttrTest2(2)]
[TAttrTest2(3)]
TMyObject = Class(TObject)
end;
{ TAttrTest2 }
constructor TAttrTest2.Create(aID: Integer);
begin
FID := aId;
end;
var
c : TRttiContext;
t : TRttiType;
a : TCustomAttribute;
begin
c := TRttiContext.Create;
try
t := c.GetType(TMyObject);
for a in t.GetAttributes do
begin
Writeln((a as TAttrTest2).ID);
end;
finally
c.Free
end;
readln;
end.
Результат: 1 type TestAttribute = class(TCustomAttribute) end; // На него можно сослаться двумя различными способами: [TestAttribute] TExample = class(Tobject) end; [Test] TExample2 = class(TObject) end; Компилятор ищет соответствующий тип, и если не находит, то автоматически добавляет "Attribute" к имени, и снова начинает искать. Это сделано для того, что бы сымитировать поведение .Net. uses
SysUtils, Rtti;
type
TestAttribute = class(TCustomAttribute)
public
constructor Create(aType : TRttiType);
end;
[Test(typeinfo(Integer))]
TEmployee = class(TObject)
end;
Существует много возможностей практического применения Атрибутов, о которых я расскажу в следующих статьях. |