delphirtti

Accessing the TList class via RTTI


I want to implement the Add method of a List type property. but i get of "Invalid class typecast" error. does anyone have an idea about this.

Company.pas

  TEmployes = class
  private
    FLastName: String;
    FFirstName: String;
  public
    property FirstName: String
      read FFirstName write FFirstName;
    property LastName: String
      read FLastName write FLastName;
  end;

  TContext = class
  private
    FEmployess: TList<TEmployes>;
  public
    constructor Create;
    destructor Destroy; override;
    property Employess: TList<TEmployes>
      read FEmployess write FEmployess;
  end;

Project1.pas

  var Context: TContext := TContext.Create;

  var rContext: TRttiContext := TRttiContext.Create;
  var rIns : TRttiInstanceType :=
    rContext.GetType(Context.ClassInfo) as TRttiInstanceType;

  for var prop in rIns.GetProperties do
  begin
    var method: TRttiMethod := prop.PropertyType.GetMethod('Add');
    var emp: TEmployes := TEmployes.Create;
    emp.FirstName := 'Username';
    method.Invoke(prop.ClassInfo, [emp]);
  end;

  Context.Free;

Solution

  • You didn't indicate which line of code is throwing the error.

    But, the way you are using RTTI to access and invoke the TList<T>.Add() method is definitely wrong. You are basically invoking RTTI to perform the equivalent of the following:

    for (<Every Property in TContext>) do
    begin
      var emp: TEmployes := TEmployes.Create;
      emp.FirstName := 'Username';
      TList<TEmployes>(TRttiProperty.ClassInfo).Add(emp);
    end;
    

    What you really need to invoke is the equivalent of the following instead:

    var Context: TContext := TContext.Create;
    
    for (However Many Employees you need) do
    begin
      var emp: TEmployes := TEmployes.Create;
      emp.FirstName := 'Username';
      Context.Employess.Add(emp);
    end;
    
    Context.Free;
    

    That means you need to actually read the Employess property of the Context object to get its TList object, and then you can call Add() on that TList object, eg:

    var Context: TContext := TContext.Create;
    
    var rContext: TRttiContext := TRttiContext.Create;
    var rIns : TRttiType := rContext.GetType(Context.ClassInfo);
    
    var prop : TRttiProperty := rIns.GetProperty('Employess');
    var method: TRttiMethod := prop.PropertyType.GetMethod('Add');
    var list : TObject := prop.GetValue(Context).AsObject;
    
    for (However Many Employees you need) do
    begin
      var emp: TEmployes := TEmployes.Create;
      emp.FirstName := 'Username';
      method.Invoke(list, [emp]);
    end;
    
    Context.Free;