You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

通过RTTI调用TList的Add方法报无效类类型转换错误如何解决

Delphi RTTI调用泛型列表Add方法报无效类类型转换解决方法

问题场景

通过RTTI反射遍历类属性、调用泛型列表类型属性的Add方法时,运行时抛出*Invalid class typecast(无效类类型转换)*错误,涉及代码如下:

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;

错误原因

核心错误有2处:

  • TRttiMethod.Invoke的第一个参数必须传入方法所属的实际对象实例,代码中传入的prop.ClassInfo是属性的RTTI类型元数据指针,不是TList<TEmployes>的实体对象,类型完全不匹配直接触发转换异常。
  • 遍历属性时未做合法性校验:如果类中存在非列表类型的属性,取Add方法会返回空引用,后续调用直接触发空指针错误。

修复方案

  1. 先通过prop.GetValue(宿主实例)从TContext对象中取出列表属性的真实实例,作为Invoke的第一个入参
  2. 调用方法前判空,过滤掉没有Add方法、属性值为空的场景
  3. 补充异常保护,避免中间出错时内存泄漏

修复后的可运行代码:

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

  for var prop in rIns.GetProperties do
  begin
    // 取属性对应的真实列表实例
    var listObj := prop.GetValue(Context).AsObject;
    if not Assigned(listObj) then Continue;

    var addMethod: TRttiMethod := prop.PropertyType.GetMethod('Add');
    if not Assigned(addMethod) then Continue;

    var emp: TEmployes := TEmployes.Create;
    emp.FirstName := 'Username';
    addMethod.Invoke(listObj, [emp]);
  end;
finally
  Context.Free;
end;

提示:如果使用的是TObjectList<T>且开启了OwnsObjects特性,列表销毁时会自动释放内部存储的对象,无需手动释放创建的TEmployes实例;如果是普通TList<T>,需要自己遍历列表释放元素避免内存泄漏。

内容的提问来源于stack exchange,提问作者DeDe

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 10:46:01