通过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方法会返回空引用,后续调用直接触发空指针错误。
修复方案
- 先通过
prop.GetValue(宿主实例)从TContext对象中取出列表属性的真实实例,作为Invoke的第一个入参 - 调用方法前判空,过滤掉没有Add方法、属性值为空的场景
- 补充异常保护,避免中间出错时内存泄漏
修复后的可运行代码:
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
相关产品推荐
相关产品推荐

