В пособии также рассматриваются анонимные методы и процедурные ссылки.
Словарь терминов
- 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 |
Это показывает, что название в себя включает между угловыми скобками полное имя фактического типа, заменяя параметр типа.
Вы также можете заметить, что тип процедурной ссылки TComparison<T> выдаст результат tkInterface, и это доказывает то, что это действительно интерфейс. |
Вот и всё что я хотел сказать об RTTI и генериках. Конечно же я не буду здесь рассказывать о других изменениях в RTTI появившихся в Delphi 2009 из-за юникодных строк.
- Оригинальный текст: Sébastien Doeraene. Copyright ©2008-2009.
- Перевод: Алексей Тимохин. Copyright ©2009.
- Дата публикации: 13 ноября 2008 года
- Дата перевода: 19 октября 2009 года.
Публикации по теме
- Подробное оглавление
- Примечания к “переводу”
- I. Введение
- II. Повседневное использование на примере TList<T>
- III. Создание обобщённого класса.
- IV. Создание обобщённой записи
- V. Ограничения обобщённых типов
- VI. Использование в качестве параметра более чем одного типа
- VII. Другие типы дженериков
- VIII. Обобщённые методы
- IX. RTTI и дженерики
- Завершающе слово и ссылка на скачивание исходников (не переведено).
Комментариев нет:
Отправить комментарий