Перевод второй статьи из цикла о RTTI в Delphi 2010.
В 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?
Атрибуты должны наследоваться от TCustomAttribute, и если вы посмотрите на описание TCustomAttribute, то вы не найдете там ничего особенного.
{Базовый класс для всех пользовательских атрибутов. Экземпляры атрибутов создаются 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, общие основы того как это работает я описал в предыдущем посте.
Для всех элементов, которые могут иметь атрибуты, имеется методом .GetAttributes(), который возвращает массив атрибутов, связанных с соответствующим элементом.
Следующий код показывает, как осуществлять доступ к атрибутам.
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
2
3
Кроме того, атрибуты имеют несколько других специфических особенностей, реализованных в компиляторе.
Допустим, у вас есть атрибут, поименованный следующим образом…
type TestAttribute = class(TCustomAttribute) end; // На него можно сослаться двумя различными способами: [TestAttribute] TExample = class(Tobject) end; [Test] TExample2 = class(TObject) end;
Компилятор ищет соответствующий тип, и если не находит, то автоматически добавляет “Attribute” к имени, и снова начинает искать. Это сделано для того, что бы сымитировать поведение .Net.
Компилятор так же реализует несколько специфическую поддержку типов, позволяющую вам легко получать TRttiType через указатель pTypeInfo.
uses SysUtils, Rtti; type TestAttribute = class(TCustomAttribute) public constructor Create(aType : TRttiType); end; [Test(typeinfo(Integer))] TEmployee = class(TObject) end;
Существует много возможностей практического применения Атрибутов, о которых я расскажу в следующих статьях.
Полный список статей из данной серии
Это всё интересно, но не понял самого главного: зачем, собственно, эти аттрибуты нужны?
Нет, ну потихоньку проясняется
http://robstechcorner.blogspot.com/2009/10/rtti-practical-examples.html
Вообще, автор обещает наглядные примеры…
Блин, ну как зачем? Это то что так необходимо, это дополнительные метаданные в твоем коде, которые ты определяешь сам. Теперь можно делать нормальные ORM на делфи или системы плагинов более навороченные. Да мало ли что еще. Атрибуты это сила.
Хм, раз атрибуты можно привязывать даже к переменным вне класса, то значит должен быть способ извлечь их.
Но я в хелпе ничего про это не нашел.
В D2010 внизу инспектора появилась дополнительная панель в описанием свойств. Скажите, можна ли при помощи атрибутов в Object Inspector создать такое описание?