Использование атрибутов и наследников 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; Существует много возможностей практического применения Атрибутов, о которых я расскажу в следующих статьях. |