我需要使用RTTI遍历一个具有复杂结构的类。这个类有几个记录成员,我也想迭代它们。
 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,以便也可以遍历记录?
发布于 2017-03-16 23:40:29
使用TValue的AsType方法将值转换为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类型为您提供灵活的运行时确定类型的功能。这个建议当然可能是错误的,但我只有问题中的一些代码摘录来指导我。
https://stackoverflow.com/questions/42838488
复制相似问题