Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
970 views
in Technique[技术] by (71.8m points)

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

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).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...