Delphi programming blog
Источник: http://teran.karelia.pro/articles/item_4467.html
 

Изучая RTTI#2

Опубликовано 18.04.2011 г. 23:09

Продолжение предыдущей заметки про RTTI и в частности атрибуты.

Атрибуты можно использовать двумя путями, первый мы в принципе рассмотрели в предыдущем примере. И суть его заключалась в том, что атрибут хранит дополнительную информацию для класса. Второй способ - использование атрибутов для "помечания" классов/методов/свойств, с тем чтобы обозначить, что они поддерживают какую то функцию. Допустим у нас есть несколько объектов: человек, кошка, билет. Можно конечно нафантазировать и более далекие вещи. Каждый из этих объектов можно назвать каким либо образом. Для человека это например пара имя+фамилия, для кошки это кличка, для билета это может быть его номер и серия. Так или иначе, можем выделить для них некоторое общее свойство - имя, название. Безусловно, для таких целей можно использовать общий родительский класс, например, какой нибудь TNamedObject, который будет иметь общее поле title или name. Либо реализовать для объектов поддержку единого интерфейса. Но есть ли смысл наследовать подобные объекты от одного предка? По факту они разнородны по своей природе. Опишем объект "Человек" с помощью класса TPerson (описания приведены не полностью):
    TPerson = class(TObject)
    ...
      public
        property name : string write FName;
        property sName : string write FSName;
        [Title]
        property FullName : string read getFullName ;
    end;
Для кошки описание будет следующим:
    TCat = class(TObject)
    ...
       public
        [Title]
        property name : string read FName write FName;
    end;
И билет имеет такой вид:
    TTicket = class(TObject)
    ...
      public
        property number  : integer read Fnumber write FNumber;
        property series  : string read Fseries write FSeries;
        [Title]
        property SNumber : string read getSNumber;
    end;
Мы видим, что за именование объекта TPerson отвечает свойство FullName, кошки - Name, билета - SNumber. За неимением общего предка, мы не можем перебрав группу объектов, получить их имена. Но тем не менее, каждый из типов предоставляет свое свойство, для получения имени, и мы можем его пометить, с помощью атрибута [Title]. Сам атрибут в данном случае является пустым классом:
    TitleAttribute = class(TCustomAttribute)
    end;
Теперь мы можем создать несколько экземпляров объектов, и получить их имена, используя атрибуты. В моем случае имена выводятся в memo на форме, при создании формы.
procedure TForm1.FormCreate(Sender: TObject);
var p : TPerson;
    c : TCat;
    t : TTicket;
begin
    p := TPerson.Create();
    p.Name := 'Иван';
    p.SName := 'Иванович';

    c := TCat.Create();
    c.name := 'Мурка';

    t := TTicket.Create();
    t.number := 123;
    t.series := 'XY';

    Browse(p);
    Browse(c);
    Browse(t);
end; 
Функция Browse должна обследовать объекты на наличие имени, и вывести его в memo. Алгоритм работы данной функции весьма прост:
  1. получить описание класса объекта и список его свойств
  2. Для каждого объекта получить список атрибутов
  3. Если атрибут описывает название объекта, то получаем значение свойства, используя TValue
procedure TForm1.Browse(obj: TObject);
var ctx : TRttiContext;
    t : TRttiType;
    a : TCustomAttribute;
    p : TRttiProperty;
    title : TValue;
begin
    ctx.Create();
    try
        t := ctx.GetType(obj.ClassType);
        for p in t.GetProperties() do begin
            for a in p.GetAttributes() do begin
                if a is TitleAttribute then begin
                    title :=  p.GetValue(obj);
                    memo1.Lines.Add(title.AsString);
                end;
            end;
        end;
    finally
        ctx.Free();
    end;
end;
результатом операций является следующий текст в memo:
Иван Иванович Мурка XY-000123
На этом вариация примера по поводу использования атрибутов для пометок членов класса заканчивается. до новых встреч (:.
Метки:  attributes  |  rtti 

Комментарии

Алексей Тимохин
04.03.2012 в 09:24
Хороший пример.
ter
04.03.2012 в 12:10
простенький очень (: дальше будет интересней (:
- Имя
- e-mail*
- Сайт
вы можете использовать теги [i],[b],[code],[quote]
Дополнительно