Как я могу убедиться, что RTTI доступен для класса, не создавая его экземпляр?

Недавно я разместил на этом форуме вопрос с просьбой дать совет относительно отсутствующей информации RTTI. в исполняемом файле DXE2.

Этот пост был урезанной версией моего настоящего дела. На помощь пришел РРУЗ, и поэтому урезанная версия была быстро решена. Однако исходная проблема все еще существует, и поэтому я публикую ее полностью. "Главный":

program MissingRTTI;
{$APPTYPE CONSOLE}
uses
  System.SysUtils, RTTI, MyUnit in 'MyUnit.pas', RTTIUtil in 'RTTIUtil.pas';
var
  RHelp:  TRttiHelper;
begin
  RHelp := TRttiHelper.Create();
  if (RHelp.IsTypeFound('MyUnit.TMyClass')) then WriteLn('TMyClass was found.')
  else WriteLn('TMyClass was not found.');
  ReadLn;
  RHelp.Free();
end.

RTTIUtil.pas:

unit RTTIUtil;
interface
uses
  MyUnit;
type
  TRttiHelper = class(TObject)
  public
    function IsTypeFound(TypeName: string) : boolean;
  end;
implementation
uses
  RTTI;
function TRttiHelper.IsTypeFound(TypeName: string): boolean;
var
  rCtx:   TRttiContext;
  rType:  TRttiType;
begin
  Result := false;
  rCtx := TRttiContext.Create();
  rType := rCtx.FindType(TypeName);
  if (rType <> nil) then
    Result := true;
  rCtx.Free();
end;
end.

и наконец MyUnit.pas:

unit MyUnit;
interface
type
  TMyClass = class(TObject)
  end;
implementation
end.

Требуемый тип не найден. Однако, если я изменю TRttiHelper.IsTypeFound так, чтобы он создавал (и немедленно освобождает) экземпляр TMyClass, тип будет найден. Вот так:

function TRttiHelper.IsTypeFound(TypeName: string): boolean;
var
  rCtx:   TRttiContext;
  rType:  TRttiType;
  MyObj:  TMyClass;
begin
  Result := false;
  MyObj:= TMyClass.Create();
  MyObj.Free();
  rCtx := TRttiContext.Create();
  ...

Итак, мне интересно, есть ли способ заставить RTTI генерироваться для TMyClass без его фактического создания?

Обновление:

С другой стороны, я мог бы упомянуть, что если я попытаюсь получить TRttiType с помощью TRttiContext.GetType, нужный тип будет найден. Так что излучается некоторый RTTI. Проверка свойства TRttiType.IsPublic, полученного TRttiContext.GetType, дает истинное значение, т.е. полученный тип является общедоступным (и, следовательно, его можно найти с помощью TRttiContext.FindType).


person conciliator    schedule 16.05.2012    source источник
comment
Возможный дубликат Delphi 2010 RTTI - RttiContext.FindType. Класс никогда не используется в приложении и удаляется компилятором.   -  person LU RD    schedule 16.05.2012
comment
Ага, это подтверждено. Спасибо @LURD. :)   -  person conciliator    schedule 16.05.2012
comment
Это одна и та же тема, @Lurd, но они не повторяются. Этот вопрос спрашивает, что происходит. Этот спрашивает, как решить эту проблему без создания экземпляра.   -  person Rob Kennedy    schedule 16.05.2012


Ответы (2)


Добавьте ссылку на класс и убедитесь, что компилятор / компоновщик не может удалить его из исполняемого файла.

unit MyUnit;

interface

type
  TMyClass = class(TObject)
  end;

implementation 

procedure ForceReferenceToClass(C: TClass);
begin
end;

initialization
  ForceReferenceToClass(TMyClass);

end.

В производственном коде вы захотите поместить ForceReferenceToClass в базовый блок, чтобы он мог использоваться совместно. Раздел инициализации модуля, в котором объявляется класс, является наиболее естественным местом для вызовов ForceReferenceToClass, поскольку в этом случае модуль является самодостаточным.

Что касается вашего наблюдения, что GetType может определить местонахождение типа, сам акт вызова GetType(TMyClass) добавляет ссылку на тип в программу. Дело не в том, что RTTI присутствует и FindType не может его найти. Напротив, включение GetType(TMyClass) добавляет RTTI к результирующей программе.

person David Heffernan    schedule 16.05.2012
comment
Спасибо Дэвиду. Ага (шлепок в лоб) - это правда, эталон конечно вызовет выброс RTTI. :) +1 - person conciliator; 16.05.2012
comment
Однако было бы неплохо, если бы Embarcadero разработал директиву компилятора, которая принудительно выводила бы данные для типов, на которые нет ссылок. У меня даже есть название: {$ FORCERTTI} и соответствующий ярлык {$ M!}. - person conciliator; 16.05.2012
comment
Достаточно вызвать какой-нибудь метод класса TMyClass (например, ClassInfo) - там нет необходимости в какой-то фиктивной подпрограмме. - person Stefan Glienke; 16.05.2012
comment
@conciliator, если вы используете директиву {$STRONGLINKTYPES ON}, будут добавлены все типы до финального exe. - person RRUZ; 16.05.2012

Я использовал {$ STRONGLINKTYPES ON} и работал очень хорошо. Поместите его на основной блок.

person Anderson    schedule 19.09.2015
comment
+1 Это включает RTTI для всех типов, которые его поддерживают. (Это правильный ответ). Это очень полезно, если вы этого хотите. Решение Дэвида Хеффернана лучше (меньший размер исполняемого файла), если вам просто нужен RTTI для небольшого количества (в противном случае) типов, на которые нет ссылок. (Я использовал это для инструмента миграции данных, импортирует / экспортирует двоичные плоские файлы, учитывая файл и имя его определения записи во время выполнения). - person John B. Lambe; 04.01.2017