delphirtti

How to retrieve the correct constructors of a class using RTTI?


I'm working with a class in Delphi defined as follows:

type
  TMyObject = class(TObject)
    constructor Create(a: string); overload; virtual;
    constructor Create(b: integer); overload; virtual;
  end;

I need to retrieve a list of constructors for TMyObject using RTTI. I attempted to use the GetMethods('Create') function of the TRttiType instance for TMyObject:

var
  Context: TRttiContext;
  RttiType: TRttiType;
  Method: TRttiMethod;
begin
  Context := TRttiContext.Create;
  RttiType := Context.GetType(TMyObject);
  for Method in RttiType.GetMethods('Create') do
  begin
    // Process method
  end;

However, I found that GetMethods('Create') also returns the Create method inherited from TObject, which isn't appropriate for creating TMyObject instances due to the additional parameters in TMyObject's constructors.

How can I use RTTI to get only the constructors of TMyObject that are usable for creating TMyObject instances? In other words, I want to exclude constructors inherited from TObject or other ancestors that cannot be used to properly initialize TMyObject. Is there a way to identify and filter out these inappropriate constructors using RTTI?

Any guidance or suggestions would be greatly appreciated.


Solution

  • Like you have noticed GetMethods function in TRttiType collects all methods in the class hierarchy.

    But there is another method GetDeclaredMethods in TRttiType that will retrieve only methods declared in particular type and will not go down the ancestor list. However, this function does not have a parameter that will allows you to filter methods by name, so to get what you need you will need to write additional filtering function.

    Something like:

    function GetDeclaredMethods(AType: TRttiType; const AName: string): TArray<TRttiMethod>;
    var
      Methods: TArray<TRttiMethod>;
      Method: TRttiMethod;
    begin
      SetLength(Result, 0);
      Methods := AType.GetDeclaredMethods;
      for Method in Methods do
        begin
          if Method.HasName(AName) then
            begin
              SetLength(Result, Length(Result) + 1);
              Result[High(Result)] := Method;
            end;
        end;
    end;
    

    Adding methods in above function is not optimized, so you might want to optimize that part, but it is also not extremely inefficient unless you have large amount of overloaded methods with same name declared in your classes.