Delphi - 将 TValue 传递给通用方法

Delphi - pass TValue to generic method

我需要使用 RTTI 遍历具有复杂结构的 class。 class 有几个我也想迭代的记录成员。

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

我知道当我在 class 中有成员时,这是一条记录:

   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 以便我也可以遍历记录?

使用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> 可能不应该是通用的 class,而是使用 RTTI 类型为您提供灵活的功能,以便 运行 时间确定的输入。这个建议当然可能是错误的,但我只有问题中的一小段代码来指导我。