我想为了调试目的将一个复杂/长记录转储到备忘录中
TmyRecord =
aValue : String
aNumber : Real;
Morenumbers : Integer ;
....
....
end;
我认为Delphi XE 2 RTTI应该让我有机会在循环中获取字段名、字段类型和值,以便将此记录写入备忘录或其他地方。
我想为了调试目的将一个复杂/长记录转储到备忘录中
TmyRecord =
aValue : String
aNumber : Real;
Morenumbers : Integer ;
....
....
end;
作为起点 - 记录简单类型。对于复杂的字段(数组、类等),请探索RTTI单元。
type
TmyRecord = record
aValue: String;
aNumber: Real;
Morenumbers: Integer;
end;
var
m: TMyRecord;
rtype: TRTTIType;
fields: TArray<TRttiField>;
i: Integer;
begin
m.aValue := 'OK';
m.aNumber := Pi;
m.Morenumbers := 666;
rtype := TRTTIContext.Create.GetType(TypeInfo(TMyrecord));
Memo1.Lines.Add(rtype.ToString);
fields := rtype.GetFields;
for i := 0 to High(fields) do
Memo1.Lines.Add(Format('%s: %s :: %s', [
fields[i].Name,
fields[i].FieldType.ToString,
fields[i].GetValue(@m).ToString]));
输出:
TmyRecord
aValue: string :: OK
aNumber: Real :: 3.14159265358979
Morenumbers: Integer :: 666
TObject
内的所有属性,因此您需要适应它以枚举记录:function EnumerateProperties(const AObject: TObject): String;
var
rt: TRttiType;
prop: TRttiProperty;
value, value2: TValue;
valstr: String;
propstr: String;
fullstr: String;
bres: Boolean;
meth: TRttiMethod;
bytes: TBytes;
bytes_arr: TArray<TBytes>;
uints: TArray<UINT32>;
C1: Integer;
begin
if not Assigned(AObject) then
Exit('');
rt := TRttiContext.Create.GetType(AObject.ClassType);
fullstr := '';
// iterate through public properties
for prop in rt.GetDeclaredProperties do
begin
value := prop.GetValue(AObject); // get property value
valstr := '?';
// check property type
case prop.PropertyType.TypeKind of
tkInteger,
tkInt64,
tkFloat: valstr := value.AsVariant;
tkString,
tkChar,
tkWChar,
tkLString,
tkWString,
tkUString: valstr := QuotedStr(value.AsString);
tkEnumeration: begin
valstr := 'ENUM';
if value.TryAsType<Boolean>(bres) then
valstr := BoolToStr(bres, TRUE)
else
begin
valstr := GetEnumName(value.TypeInfo, prop.GetValue(AObject).AsOrdinal);
end;
end;
tkClass: begin
// check if property is TList or any of its descendants,
// then iterate through each of it's members
meth := prop.PropertyType.GetMethod('ToArray');
if Assigned(meth) then
begin
value2 := meth.Invoke(value, []);
Assert(value2.IsArray);
for C1 := 0 to value2.GetArrayLength - 1 do
valstr := valstr + Format('(%s), ', [EnumerateProperties(value2.GetArrayElement(C1).AsObject)]);
if valstr <> '' then
Delete(valstr, Length(valstr) - 1, 2);
valstr := Format('[%s]', [valstr]);
end
else // otherwise, process it as normal class
valstr := Format('[%s]', [EnumerateProperties(value.AsObject)]);
end;
// dynamic arrays
tkDynArray: begin
if value.TryAsType<TBytes>(bytes) then // TBytes
valstr := BytesToHex(bytes)
else
if value.TryAsType<TArray<TBytes>>(bytes_arr) then // TArray<TBytes>
begin
valstr := '';
for C1 := Low(bytes_arr) to High(bytes_arr) do
valstr := valstr + QuotedStr(BytesToHex(bytes_arr[C1])) + ', ';
if valstr <> '' then
Delete(valstr, Length(valstr) - 1, 2);
valstr := Format('(%s)', [valstr]);
end
else
if value.TryAsType<TArray<UINT32>>(uints) then // TArray<UINT32>
begin
valstr := '';
for C1 := Low(uints) to High(uints) do
valstr := valstr + IntToStr(uints[C1]) + ', ';
if valstr <> '' then
Delete(valstr, Length(valstr) - 1, 2);
valstr := Format('(%s)', [valstr]);
end;
end;
tkUnknown: ;
tkSet: ;
tkMethod: ;
tkVariant: ;
tkArray: ;
tkRecord: ;
tkInterface: ;
tkClassRef: ;
tkPointer: ;
tkProcedure: ;
end;
propstr := Format('%s: %s', [prop.Name, valstr]);
fullstr := fullstr + propstr + '; ';
end;
if fullstr <> '' then
Delete(fullstr, Length(fullstr) - 1, 2);
result := fullstr;
end;