Блог Александра Божко
Архивы
Рубрики
Поделись с другими!
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

Перевод второй статьи из цикла о 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;

Существует много возможностей практического применения Атрибутов, о которых я расскажу в следующих статьях.

Полный список статей из данной серии

Новинки литературы:


Поделись с другими!
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  
  •  

5 комментариев: Использование атрибутов и наследников TCustomAttribute

  • Это всё интересно, но не понял самого главного: зачем, собственно, эти аттрибуты нужны?

  • Нет, ну потихоньку проясняется
    http://robstechcorner.blogspot.com/2009/10/rtti-practical-examples.html
    Вообще, автор обещает наглядные примеры…

  • Блин, ну как зачем? Это то что так необходимо, это дополнительные метаданные в твоем коде, которые ты определяешь сам. Теперь можно делать нормальные ORM на делфи или системы плагинов более навороченные. Да мало ли что еще. Атрибуты это сила.

  • Хм, раз атрибуты можно привязывать даже к переменным вне класса, то значит должен быть способ извлечь их.
    Но я в хелпе ничего про это не нашел.

  • В D2010 внизу инспектора появилась дополнительная панель в описанием свойств. Скажите, можна ли при помощи атрибутов в Object Inspector создать такое описание?

Оставить комментарий

Ваш email не будет опубликован. Обязательные поля отмечены *

Вы можете использовать это HTMLтеги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Продукты DevArt
Купить онлайн:



Читай русскоязычные Delphi блоги
Каталог блогов Blogdir.ru
Яндекс.Метрика