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

Наскоро публикувах въпрос в този форум с молба за всякакви съвети относно липсваща RTTI информация в DXE2 изпълним файл.

Тази публикация беше съкратена версия на действителния ми случай. RRUZ се притече на помощ и така съкратената версия беше бързо разрешена. Първоначалният проблем обаче все още стои, така че сега го публикувам изцяло. "Главен":

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 за всички типове, които го поддържат. (Това е правилен отговор). Много е полезно, ако това е, което искате. Решението на David Heffernan е по-добро (по-малък размер на изпълним файл), ако просто искате RTTI за малък брой (иначе) нереферирани типове. (Използвах това за инструмент за мигриране на данни, импортира/експортира двоични плоски файлове, като се има предвид файла и името на неговата дефиниция на запис по време на изпълнение). - person John B. Lambe; 04.01.2017