Delphi-将TValue传递给泛型方法
我需要使用RTTI迭代一个具有复杂结构的类。这个类有几个记录成员,我也想迭代这些成员Delphi-将TValue传递给泛型方法,delphi,rtti,delphi-10.1-berlin,Delphi,Rtti,Delphi 10.1 Berlin,我需要使用RTTI迭代一个具有复杂结构的类。这个类有几个记录成员,我也想迭代这些成员 TRTTIHelpers<T> = class public class function DoGetValuesForClass(aClassInst: T): TStringList; class function DoGetValuesForRecord(aRec: T): TStringList; end; TRTTIHelpers=class 公众的 类函数Do
TRTTIHelpers<T> = class
public
class function DoGetValuesForClass(aClassInst: T): TStringList;
class function DoGetValuesForRecord(aRec: T): TStringList;
end;
TRTTIHelpers=class
公众的
类函数DoGetValuesForClass(aClassInst:T):TStringList;
类函数DoGetValuesForRecord(aRec:T):TStringList;
结束;
我知道当我班上有一个记录在案的成员时:
for prop in rt.GetProperties() do
begin
if prop.PropertyType is TRttiRecordType then
begin
lValue := prop.GetValue(aInst);
Result.AddStrings(TRTTIHelpers<T>.DoGetValuesForRecord(TValue)); <--
end
rt.GetProperties()do中的prop的
开始
如果prop.PropertyType为TRttiRecordType,则
开始
左值:=属性GetValue(aInst);
Result.AddStrings(TRTTIHelpers.DoGetValuesForRecord(TValue)) 使用TValue
的方法将值强制转换为T
:
lValue := prop.GetValue(aInst);
Result.AddStrings(TRTTIHelpers<T>.DoGetValuesForRecord(lValue.AsType<T>));
lValue:=prop.GetValue(aInst);
AddStrings(TRTTIHelpers.DoGetValuesForRecord(lValue.AsType));
这个简单的程序演示了这一点:
{$APPTYPE CONSOLE}
uses
System.RTTI;
type
TMyRecord = record
foo: Integer;
end;
TMyClass = class
function GetRec: TMyRecord;
property Rec: TMyRecord read GetRec;
function GetInt: Integer;
property Int: Integer read GetInt;
end;
function TMyClass.GetRec: TMyRecord;
begin
Result.foo := 42;
end;
function TMyClass.GetInt: Integer;
begin
Result := 666;
end;
procedure Main;
var
inst: TMyClass;
ctx: TRttiContext;
typ: TRttiType;
prop: TRttiProperty;
value: TValue;
rec: TMyRecord;
begin
inst := TMyClass.Create;
typ := ctx.GetType(TypeInfo(TMyClass));
for prop in typ.GetProperties do begin
if prop.Name='Rec' then begin
value := prop.GetValue(inst);
rec := value.AsType<TMyRecord>;
Writeln(rec.foo);
end;
end;
end;
begin
try
Main;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
{$APPTYPE控制台}
使用
System.RTTI;
类型
TMyRecord=记录
foo:整数;
结束;
TMyClass=类
函数GetRec:TMyRecord;
财产记录:TMyRecord read GetRec;
函数GetInt:Integer;
属性Int:整数读取GetInt;
结束;
函数TMyClass.GetRec:TMyRecord;
开始
Result.foo:=42;
结束;
函数TMyClass.GetInt:Integer;
开始
结果:=666;
结束;
主程序;
变量
研究所:TMyClass;
ctx:trtti上下文;
类型:trtti型;
财产:信托财产;
价值:TValue;
记录:TMyRecord;
开始
inst:=TMyClass.Create;
typ:=ctx.GetType(TypeInfo(TMyClass));
对于typ.GetProperties中的prop,请不要开始
如果prop.Name='Rec',则开始
值:=属性获取值(inst);
rec:=value.AsType;
书面文件(rec.foo);
结束;
结束;
结束;
开始
尝试
主要的;
除了
关于E:Exception-do
Writeln(E.ClassName,“:”,E.Message);
结束;
Readln;
结束。
当然,这确实需要属性prop
的类型正确。如果没有,那么您将遇到运行时错误。在上面的示例中,我通过测试属性的名称来确保获得所需的属性,从而确保这一点。如果删除该测试,则程序将失败,并出现运行时EInvalidCast
错误
看看你的代码,我怀疑你很可能会遇到这样的错误。如果rt
的每个属性都是相同的类型,我会感到惊讶
查看TRTTIHelpers
我认为它目前的形式对您没有多大帮助。至少,您知道它不会与基于RTTI的代码很好地交互。原因是对TRTTIHelpers
的调用要求您在编译时提供类型参数。但对于RTTI代码,您在编译时不知道该类型。我怀疑TRTTIHelpers
可能不应该是一个泛型类,而是使用RTTI类型为您提供灵活的运行时确定类型的功能。这个建议当然可能是错误的,但我只有问题中的一小部分代码来指导我。好吧,这就是你所问问题的答案。运行时错误告诉您,lValue
中的内容不是类型T
。lValue中的内容是类型TRTTIRecordType-如果prop.PropertyType是TRTTIRecordType,那么-我的类中有一个记录类型Yes,一个记录类型。但是,正如运行时错误告诉您的那样,不一定与泛型T
的类型相同。我的代码基本上与您发布的代码相同,只是我希望从行值传递值:=prop.GetValue(inst);作为另一个函数的泛型类型。这可能吗?我答案中的代码证明它是正确的。你的错误肯定是一个基本的理解,如果你不理解,你就不会取得进步。不要想象一些神奇的代码块会解开你的枷锁。您认为lValue
包含类型为T
的记录,但系统告诉您它没有。信任这个系统。您询问如何从TValue
中提取特定类型的值,我的回答清楚地说明了这一点。现在由您来调试您的程序。