delphigenericsrtti

RTTI not available for methods of instantiated Generic class


I am trying to retrieve RTTI information for an instantiated Generic class using Delphi 12.2 Pro.

The Delphi documentation states:

https://docwiki.embarcadero.com/RADStudio/Athens/en/Overview_of_Generics

Run-time type identification

In Win32, generics and methods do not have run-time type information (RTTI), but instantiated types do have RTTI.

I can get RTTI information for fields and properties of instantiated Generic classes. However, I can't get RTTI for methods. Below is a sample code. Am I missing something, or is this a bug?

program Project1;

{$M+}

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  System.Rtti;

type
  TTestObject<T> = class
  private
    FValue: T;
    function GetValue: T;
  public
    constructor Create(AValue: T);
    property Value: T read GetValue;
  end;

  TIntegerObject = class(TTestObject<Integer>)
  end;

{ TTestObject }

constructor TTestObject<T>.Create(AValue: T);
begin
  FValue := AValue;
end;

function TTestObject<T>.GetValue: T;
begin
  Result := FValue;
end;

var
  t: TRttiType;
  m: TRttiMethod;
  o: TIntegerObject;
  n: string;
begin
  try
    o := nil;
    n := '?';
    with TRttiContext.Create do
    try
      o := TIntegerObject.Create(10);
      t := GetType(o.ClassType);
      for m in t.GetMethods do
      begin
        if (m.name = 'GetValue') then
        begin
          n := m.Name;
          break;
        end;
      end;
      WriteLn('Name: ' + n); //writes "Name: ?"
      ReadLn;
    finally
      o.free;
      Free;
    end;
  except
    on E: Exception do
    begin
      Writeln(E.ClassName, ': ', E.Message);
      ReadLn;
    end;
  end;
end.

Solution

  • You are not getting RTTI information for GetValue method because it is declared as private and default Delphi RTTI configuration does not include private methods.

    There is following declaration in System unit which is then used in RTTI compiler directive to define default RTTI configuration.

    const
      { These constants represent the default settings built into the compiler.
        For classes, these settings are normally inherited from TObject. }
      DefaultMethodRttiVisibility = [vcPublic, vcPublished];
      DefaultFieldRttiVisibility = [vcPrivate..vcPublished];
      DefaultPropertyRttiVisibility = [vcPublic, vcPublished];
    

    To change the visibility in your code, you need to use RTTI compiler directive in each unit where you want them to be different than default ones.

    For instance, using following will enable RTTI for everything and you will get RTTI for GetValue function.

    {$RTTI EXPLICIT METHODS([vcPrivate..vcPublished]) PROPERTIES([vcPrivate..vcPublished]) FIELDS([vcPrivate..vcPublished])}
    

    You can find more information about specific settings and how to use RTTI in official documentation RTTI Directive