How can I make sure RTTI is available for a class without instantiating it?

delphi, delphi-xe2, rtti

Solution

Add a reference to the class and make sure that the compiler/linker cannot strip it from the executable.

unit MyUnit;

interface

type
  TMyClass = class(TObject)
  end;

implementation 

procedure ForceReferenceToClass(C: TClass);
begin
end;

initialization
  ForceReferenceToClass(TMyClass);

end.

In production code you would want to place `ForceReferenceToClass` in a base unit so that it could be shared. The initialization section of the unit that declares the class is the most natural place for the calls to `ForceReferenceToClass` since the unit is then self-contained.

Regarding your observation that `GetType` can locate the type, the very act of calling `GetType(TMyClass)` adds a reference to the type to the program. It's not that the RTTI is present and `FindType` cannot find it. Rather, the inclusion of `GetType(TMyClass)` adds the RTTI to the resulting program.

Problem

I've recently posted a question in this forum asking for any advice regarding missing RTTI information in a DXE2 executable. That post was a stripped down version of my actual case. RRUZ came to the rescue, and so the stripped down version was quickly resolved. The original problem, though, is still standing, and so I'm posting it in full now. "Main": ``` 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. ``` and finally `MyUnit.pas`: ``` unit MyUnit; interface type TMyClass = class(TObject) end; implementation end. ``` The desired type is not found. However, if I change `TRttiHelper.IsTypeFound` so that it instantiates (and immediately frees) an instance of `TMyClass`, the type is found. Like so: ``` function TRttiHelper.IsTypeFound(TypeName: string): boolean; var rCtx: TRttiContext; rType: TRttiType; MyObj: TMyClass; begin Result := false; MyObj:= TMyClass.Create(); MyObj.Free(); rCtx := TRttiContext.Create(); ... ``` So I'm wondering, is there any way I can force RTTI to be emitted for `TMyClass` without actually instantiating it? Update: On a side not, I might mention that if I try to fetch the TRttiType using `TRttiContext.GetType`, the desired type is found. So there is some RTTI emitted. Checking the `TRttiType.IsPublic` property as retrieved by `TRttiContext.GetType` yields a true value, i.e. the retrieved type is public (and hence should be possible to locate using `TRttiContext.FindType`).

Original source

Related problems