Страницы

понедельник, 19 октября 2009 г.

Дженерики в Delphi 2009 для Win32. Часть 7. RTTI и генерики.

В пособии также рассматриваются анонимные методы и процедурные ссылки.



Словарь терминов
  • generics - дженерики, генерики, параметризованные классы, шаблоны, обобщения;
  • actual types – фактические типы
  • generic class – обобщённый класс;
  • generic parameter – обобщённый параметр;
  • anonymous routines - анонимные методы;
  • routine references - процедурные ссылки;

IX. RTTI и генерики

В этой последней главе, я собираюсь рассказать о том, что генерики изменили в RTTI. Если Вы никогда не игрались с RTTI, Вы можете пропустить эту главу. Она не была задумана как введение в RTTI.

IX-A. Изменения в псевдо-процедуре TypeInfo

RTTI всегда начинается с псевдо процедуры TypeInfo. Вы наверное знаете, что определённые типы не могут передаваться в эту псевдо процедуру. Например, указатели. И поэтому, она никогда не возвращает nil.

Итак, можем ли мы вызвать TypeInfo для обобщённого типа T? Вопрос уместный: ведь T может быть указателем (не валидным для TypeInfo) или целым (integer) (валидный).

Ответом будет да, разрешается вызывать TypeInfo для обобщённого типа. Но что случится, если T окажется типом, который не имеет RTTI? Именно в этом единственном случае, TypeInfo вернёт nil.

Чтобы проиллюстрировать этот феномен, вот метода небольшого класса, который печатает имя и тип типа, но делает это с помощью дженериков:

type
  TRTTI = class(TObject)
  public
    class procedure PrintType<T>; static;
  end;

class procedure TRTTI.PrintType<T>;
var
  Info: PTypeInfo;
begin
  Info := TypeInfo(T); // warning ! Info may be nil here

  if Info = nil then
    WriteLn('This type has no RTTI')
  else
    WriteLn(Info.Name, #9, GetEnumName(TypeInfo(TTypeKind), Byte(Info.Kind)));
end;

Этот метод, довольно специфичен. В том смысле, что его реальный параметр в действительности передаётся как параметризованный тип.

begin
  TRTTI.PrintType<Integer>;
  TRTTI.PrintType<TObject>;
  TRTTI.PrintType<Pointer>;
end;

Выполнение его даёт результат:

Integer tkInteger
TObject tkClass
This type has no RTTI

IX-A-1. Более общая функция TypeInfo

Я уже пожалел, что TypeInfo не может быть применена к любому типу, даже в случае, если результатом будет nil; может и вы сделали также. Поэтому, вот небольшая замена этого метода методом, решающим эту проблему.

type
  TRTTI = class(TObject)
  public
    class procedure PrintType<T>; static;
    class function TypeInfo<T>: PTypeInfo; static;
  end;

class function TRTTI.TypeInfo<T>: PTypeInfo;
begin
  Result := System.TypeInfo(T);
end;

Вы можете использовать его так:

Info := TRTTI.TypeInfo<Pointer>; // Info = nil
// вместо:
Info := TypeInfo(Pointer); // ошибка компилятора, так как у указателя (Pointer) нет RTTI

IX-B. Есть ли RTTI у обобщённых типов?

На самом деле здесь два вопроса: есть ли RTTI у неопределённых обобщённых типов (тех, у которых не определён параметр T)? И есть ли RTTI у определённых обобщённых типов (тех, у которых T было заменено реальным типом, таким как Integer)?

Самый простой способ узнать это – попробовать самим ;-) Взгляните на простой тест для определённых обобщённых типов. На самом деле, это вполне логично, так как неопределённые обобщённые типы, на самом деле не являются реальными типами, а скорее шаблонами типов, и они перестают существовать, после окончания компиляции.

Можно спросить себя, какое название будет у такого типа. Итак:

begin
  TRTTI.PrintType<TComparison<Integer>>;
  TRTTI.PrintType<TTreeNode<Integer>>;
end;

И результат:

TComparison<System.Integer> tkInterface
TTreeNode<System.Integer> tkClass

Это показывает, что название в себя включает между угловыми скобками полное имя фактического типа, заменяя параметр типа.

info

Вы также можете заметить, что тип процедурной ссылки TComparison<T> выдаст результат tkInterface, и это доказывает то, что это действительно интерфейс.

Вот и всё что я хотел сказать об RTTI и генериках. Конечно же я не буду здесь рассказывать о других изменениях в RTTI появившихся в Delphi 2009 из-за юникодных строк.



Публикации по теме

Комментариев нет:

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