I have a very complex nested record type. I need to monitor changes in values of it's fields after a method call. I used RTTI to do that (originally copied from here):
procedure CompareFields(const Rec1, Rec2: Pointer; const RectTypeInfo: TRttiType;
const BaseName: string; const BaseOffset: Integer; const Lines: TStrings);
var
R1Field, R2Field: Pointer;
MyField: TRttiField;
State: string;
Path: string;
begin
if RectTypeInfo.TypeKind = tkRecord then
begin
for MyField in RectTypeInfo.GetFields do
begin
R1Field := Pointer(Integer(Rec1) + BaseOffset + MyField.Offset);
R2Field := Pointer(Integer(Rec2) + BaseOffset + MyField.Offset);
if CompareMem(R1Field, R2Field, MyField.FieldType.TypeSize) then
State := '=='
else
State := '<>';
Path := BaseName + '.' + MyField.Name;
Lines.Add(Format('%2s | %-20s | +%2d | %10s[%2d] | %22s | %22s', [State, Path,
BaseOffset + MyField.Offset,
MyField.FieldType.ToString,
MyField.FieldType.TypeSize,
MyField.GetValue(R1Field).ToString,
MyField.GetValue(R2Field).ToString]));
if MyField.FieldType.TypeKind = tkRecord then
CompareFields(Rec1, Rec2, MyField.FieldType, Path, BaseOffset + MyField.Offset, Lines);
end;
end;
end;
The CompareMem
part works fine and clearly indicates the fields that have been changed. But the problem is about reporting values of tow record. MyField.GetValue(R1Field).ToString
some times return a random value and that's because MyField.GetValue(R1Field)
fill the result with random values.
This is a sample that demonstrates the problem:
type
TMyRec1 = record
F11: Integer;
F12: Boolean;
F13: Double;
end;
TMyRec2 = record
F21, F22: TMyRec1;
F23: Integer;
F24: TMyRec1;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
MyContext: TRttiContext;
Rec1, Rec2: TMyRec2;
begin
FillChar(Rec1, SizeOf(Rec1), #0);
FillChar(Rec2, SizeOf(Rec1), #0);
CompareFields(@Rec1, @Rec2, MyContext.GetType(TypeInfo(TMyRec2)), 'TMyRec2', 0,
Memo1.Lines);
end;
and the result is:
== | TMyRec2.F21 | + 0 | TMyRec1[16] | (record) | (record)
== | TMyRec2.F21.F11 | + 0 | Integer[ 4] | 0 | 0
== | TMyRec2.F21.F12 | + 4 | Boolean[ 1] | False | False
== | TMyRec2.F21.F13 | + 8 | Double[ 8] | 0 | 0
== | TMyRec2.F22 | +16 | TMyRec1[16] | (record) | (record)
== | TMyRec2.F22.F11 | +16 | Integer[ 4] | 0 | 0
== | TMyRec2.F22.F12 | +20 | Boolean[ 1] | False | False
== | TMyRec2.F22.F13 | +24 | Double[ 8] | 0 | 0
== | TMyRec2.F23 | +32 | Integer[ 4] | 21013568 | 0 <<--
== | TMyRec2.F24 | +40 | TMyRec1[16] | (record) | (record)
== | TMyRec2.F24.F11 | +40 | Integer[ 4] | 0 | 0
== | TMyRec2.F24.F12 | +44 | Boolean[ 1] | False | False
== | TMyRec2.F24.F13 | +48 | Double[ 8] | 9.92338439963001E-303 | 0 <<--
As you can see TMyRec2.F23
and TMyRec2.F24.F13
seem to have values other than '0' even after calling FillChar
!