Delphi - передать TValue универсальному методу
Мне нужно перебрать класс, который имеет сложную структуру, используя 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, чтобы я также мог перебирать запись?
1 ответ
Использовать AsType<T>
метод TValue
бросить значение в 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, чтобы предложить вам функциональность, гибкую для типизации, определенной во время выполнения. Этот совет, конечно, может быть неправильным, но у меня есть только небольшие фрагменты кода в этом вопросе, чтобы направлять меня.