2017-03-16 172 views
2

我需要遍历一个使用RTTI具有复杂结构的类。该类有几个记录成员,我也想迭代。Delphi - 将TValue传递到泛型方法

TRTTIHelpers<T> = class 
    public 
    class function DoGetValuesForClass(aClassInst: T): TStringList; 
    class function DoGetValuesForRecord(aRec: T): TStringList; 
    end; 

我知道当我在这是一个创纪录的类成员:

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 

我怎样才能通过TValue作为参数传递给DoGetValuesForRecord,所以我也可以通过记录重复?

回答

7

使用的TValueAsType<T>方法将值转换为T

lValue := prop.GetValue(aInst); 
Result.AddStrings(TRTTIHelpers<T>.DoGetValuesForRecord(lValue.AsType<T>)); 

这个简单的程序说明了这一点:

{$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. 

当然,这并不需要的财产prop是的正确的类型。如果没有,那么你会遇到运行时错误。在我上面的示例中,我确保通过测试属性的名称来确保获得所需的属性。如果删除该测试,则程序将失败,并显示运行时间为EInvalidCast的错误。

看着你的代码我怀疑你很可能会遇到这样的错误。如果rt的每一个财产属于同一类型,那将是令人惊讶的。

看着TRTTIHelpers<T>我认为这对你目前的形式不会很有用。至少,你将无法与基于RTTI的代码良好地交互。原因是调用TRTTIHelpers<T>需要您在编译时提供类型参数。但是对于RTTI代码,在编译时你不知道这种类型。我怀疑TRTTIHelpers<T>应该不是泛型类,而是使用RTTI类型为您提供功能,这对于运行时确定的键入来说是灵活的。这个建议当然可能是错误的,但是我只有这个问题中的一小段代码来指导我。

+0

嗯,这是你问的问题的答案。运行时错误告诉你,无论'lValue'是什么,都不是'T'类型。 –

+0

lValue中的内容是TRTTIRecordType类型 - 如果prop.PropertyType是TRttiRecordType,那么 - 并且我在我的类中有记录类型 – RBA

+0

是,记录类型。但不一定与通用'T'类型相同,因为运行时错误会通知您。 –