Delphi RTTI. Что хранится в tkPointer? Как с помощью RTTI получить значение в p: PInteger;?
Не могу понять, как в RTTI получить значение переменной если она указана как ссылка tkPointer? Т.е есть:
type
TRec = record
i: Integer;
p: PInteger;
end;
Как с помощью RTTI получить значение в p: PInteger;, не ссылку а число p^.
Я конечно могу вот так, но это только для PInteger а нужно для всех ссылок что не являются Pointer и PPointer.
ValuePointer := TValue(V).AsType<Pointer>;
if ValuePointer <> nil then
Value := PInteger(ValuePointer)^;
Пишу парсер классов и record вот покажу часть кода:
procedure TAmToJsonVariableRtti.AddJsonValue(P:PParam;F:TJsonDataValueHelper;V :TValue; LastType:TRttiType);
var Dym:TRttiDynamicArrayType;
i,Count:integer;
VA :TValue;
rttiContext : TRttiContext;
s,AName:string;
RTyp:TRttiType;
enumBuffer: set of Byte;
enumType: PTypeInfo;
enumData: PTypeData;
enumDenLimiter:boolean;
begin
{ TTypeKind = (tkUnknown, tkInteger, tkChar, tkEnumeration, tkFloat,
tkString, tkSet, tkClass, tkMethod, tkWChar, tkLString, tkWString,
tkVariant, tkArray, tkRecord, tkInterface, tkInt64, tkDynArray, tkUString,
tkClassRef, tkPointer, tkProcedure, tkMRecord);}
case V.Kind of
tkInterface : begin
if V.AsInterface is tOBJECT then
begin
if P.Level>P.MaxLevel then
begin
F.Value:='[break:MaxLevel:tkInterface]';
exit;
end;
inc(P.Level);
try
if P.NeedNameType then
AName:='Object:'+ TObject(V.AsInterface).ClassName
else
AName:= 'Object';
RTyp:= rttiContext.GetType(TObject(V.AsInterface).ClassInfo);
ParsJsonValue(P,F.ObjectValue[AName].ObjectValue,TObject(V.AsInterface),RTyp);
finally
dec(P.Level);
end;
// F.Value:= TObject(V.AsInterface).ClassName;
end;
end;
tkInteger : F.IntValue:= V.AsInteger;
tkPointer : begin
F.IntValue:= V.AsInteger;
F.Value:= '$'+ IntToHex(Integer(V.AsType<Pointer>));
end;
tkEnumeration : begin
F.Value:= GetEnumName(V.TypeInfo, V.AsOrdinal);
end;
tkFloat : begin
if V.TypeInfo = TypeInfo(TDateTime) then
F.DateTimeValue:= V.AsExtended
else
F.FloatValue:= V.AsExtended;
end;
tkSet : begin
V.ExtractRawData(@enumBuffer);
if V.TypeInfo=nil then exit;
if V.TypeInfo.TypeData=nil then exit;
if V.TypeInfo.TypeData.CompType=nil then exit;
enumType := V.TypeInfo.TypeData.CompType^;
if enumType=nil then exit;
enumData := enumType.TypeData;
if enumData=nil then exit;
s:=V.TypeInfo.Name+':[';
enumDenLimiter:=false;
for i := enumData.MinValue to enumData.MaxValue do
if i in enumBuffer then
begin
if enumDenLimiter then
s:= s+', ';
s:= s+ GetEnumName(enumType, i);
enumDenLimiter:=true;
end;
s:= s+']';
F.Value:= s;
end;
tkVariant : F.VariantValue:= V.AsVariant;
tkInt64 : F.LongValue:= V.AsInt64;
tkChar,
tkWChar,
tkLString,
tkWString,
tkUString,
tkString : F.Value:= V.AsString;
tkMRecord,
tkRecord : begin
if P.Level>P.MaxLevel then
begin
F.Value:='[break:MaxLevel:tkRecord]';
exit;
end;
inc(P.Level);
ParsJsonValue(P, F.ObjectValue,V.GetReferenceToRawData,LastType);
dec(P.Level);
end;
tkClass : begin
if P.Level>P.MaxLevel then
begin
F.Value:='[break:MaxLevel:tkClass]';
exit;
end;
inc(P.Level);
ParsJsonValue(P, F.ObjectValue,V.AsObject,LastType);
dec(P.Level);
end;
tkDynArray,
tkArray : begin
if P.Level>P.MaxLevel then
begin
F.Value:='[break:MaxLevel:tkArray]';
exit;
end;
Count:= V.GetArrayLength;
F.ArrayValue.Count:=Count;
for I := 0 to Count-1 do
begin
VA:=V.GetArrayElement(i);
// s:=VA.TypeInfo.Name;
RTyp:= rttiContext.GetType(VA.TypeInfo);
if (RTyp<> nil) then
begin
inc(P.Level);
AddJsonValue(P,F.ArrayValue[i],VA,RTyp);
dec(P.Level);
end;
end;
end;
end;
end;
в строке
tkPointer : begin
F.IntValue:= V.AsInteger;
F.Value:= '$'+ IntToHex(Integer(V.AsType<Pointer>));
end;
я могу только значение адреса а как сам тип данным получить что бы его пропарсить?
а хочу что бы pinteger имел значение числа
проблема еше в том что тот модуль где этот код будет не может знать всех возможных типов например я не могу там написать
if V is PInteger then else if V is PBoolean then.....
т.к это будет работать только для PInteger и PBoolean нужно как то для всех возможных ссылок код придумать
УРА! нашел решение
tkPointer : begin
Ps:= V.AsType<Pointer>;
if (V.TypeInfo <> typeinfo(Pointer)) and (V.TypeInfo <> typeinfo(PPointer)) then
begin
enumType := V.TypeInfo.TypeData.RefType^;
RTyp:= rttiContext.GetType(enumType);
AName:= 'Type:'+enumType.Name;
if Ps<>Pointer($FFFFFFFF) then
begin
try
TValue.Make(
Ps,
enumType,
VA);
except
Ps:=nil;
end;
end
else
begin
end;
end
else
begin
Ps:=nil;
end;
F.ObjectValue['Addr'].Value:= '$'+ IntToHex(Integer(V.AsType<Pointer>));
try
if (Ps <> nil) and (Ps<>Pointer($FFFFFFFF)) and (RTyp<>nil) then
AddJsonValue(P,F.ObjectValue[AName],VA,RTyp);
except
Ps:=nil;
end;
//ParsJsonValue(P,F.ObjectValue[AName].ObjectValue,TObject(V.AsInterface),RTyp);
// F.IntValue:= VA.AsInteger;
// F.Value:= '$'+ IntToHex(Integer(V.AsType<Pointer>));
end;
