包含记录指针的访问冲突 RTTI 转储记录

Access violation RTTI dumping record containing record pointers

uses RTTI;

type TMyRecord = packed record
  name : String[20];
  age  : Integer;
end;

type TMasterCtrl = packed record
  MyRecord: ^TMyRecord;  // Error can be avoided by changing to `MyRecord: Pointer;`
end;

procedure RTTIDump(Instance, ATypeInfo: Pointer; Memo: TStrings; NameWidth, FieldTypeWidth, ValueWidth: Integer; PaddingChar: Char);
var
  rType: TRTTIType;
  fields: TArray<TRttiField>;
  i: Integer;
begin
  rType := TRTTIContext.Create.GetType(ATypeInfo);
  Memo.Add(rType.ToString);
  fields := rType.GetFields;
  for i := 0 to High(fields) do
    Memo.Add(Format('%s: %s :: %s', [
      fields[i].Name.PadRight(NameWidth, PaddingChar),
      fields[i].FieldType.ToString.PadRight(FieldTypeWidth, PaddingChar),
      fields[i].GetValue(Instance).ToString.PadRight(FieldTypeWidth, PaddingChar) ]));
end;

procedure TForm3.Button2Click(Sender: TObject);
var
  myRecord    : TMyRecord;
  MasterCtrl: TMasterCtrl;
begin
myRecord.name := 'Fred Bloggs';
myRecord.age  := 23;

MasterCtrl.MyRecord := @myRecord;

RTTIDump(Addr(MasterCtrl), TypeInfo(TMasterCtrl), Memo1.Lines, 18, 18, 0, ' ');
end;

如何解决此代码将创建的访问冲突,仍然使用指向记录的指针?

您需要为指针使用正确的类型声明。

type
  PMyRecord =^TMyRecord;
  TMyRecord = packed record
  name : String[20];
  age  : Integer;
end;

type TMasterCtrl = packed record
  MyRecord: PMyRecord;  
end;

正如 LU RD 所说,您必须为 TMyRecord 声明一个正确的指针类型才能为 TMasterCtrl.MyRecord 字段生成正确的 RTTI,否则 field[s].FieldType 属性 崩溃,因为没有要检索的类型信息。

type
  PMyRecord = ^TMyRecord; // <-- here
  TMyRecord = packed record
    name : String[20];
    age  : Integer;
  end;

  TMasterCtrl = packed record
    MyRecord: PMyRecord;  
  end;

也就是说,您的代码还有另外两个问题:

  1. fields[i].GetValue(@Instance)

    Instance 已经包含 TMasterCtrl 实例的地址。通过使用 @,您将错误的地址传递给 GetValue()。您需要删除 @:

     fields[i].GetValue(Instance)
    
  2. 不叫rType.FreeTRttiContext 拥有它并将免费为您提供。