EInsufficientRTTI异常,消息"可用于支持此操作的RTTi不足"

Las*_*ing 2 delphi rtti delphi-10.1-berlin

试图在运行时将对象转换为JSON,我得到的RTTI错误不足.对象是:

{$M+}
{$TYPEINFO ON}
{$METHODINFO ON}
{$RTTI EXPLICIT METHODS([vcPublic, vcPublished]) PROPERTIES([vcPublic, vcPublished])}

TMyPacket = class(TObject)
  Private
    FID: TGUID;
    FToIP: string;
    FToPort: integer;
    FSent: boolean;
    FSentAt: TDateTime;
    FAck: boolean;
    FTimeOut: Cardinal;
    FDataToSendSize: UINT64;
    FDataToSend: AnsiString;
  public
    constructor create;
    destructor free;
  published
    property ID: TGUID read FID write FID;
    property ToIP: string read FToIP write FToIP;
    property ToPort: integer read FToPort write FToPort;
    property Sent: boolean read FSent write FSent;
    property SentAt: TDateTime read FSentAt write FSentAt;
    property Ack: boolean read FAck write FAck;
    property TimeOut: Cardinal read FTimeOut write FTimeOut;
    property DataToSend: AnsiString read FDataToSend write FDataToSend;
  end;
Run Code Online (Sandbox Code Playgroud)

稍后在代码中:

var fpacket: TMYPacket;
begin     
fpacket := TVWTCPPacket.create;
//assign value to class properties
memo1.Lines.Text := TJson.ObjectToJsonString(fpacket); //throws error
Run Code Online (Sandbox Code Playgroud)

并获得JSON转换的错误.有没有人知道Delphi Berlin 10.1出了什么问题?我确实记得XE2上的一些RTTI问题,但不确定上面发生的事情是否与Delphi旧bug有关.

Ste*_*nke 6

进入System.RttiTRttiField.GetValue在该行if ft = nil then放置一个断点并设置一个断点条件ft = nil(如果你将断点放在下一行,你将无法看到由于优化而得到的字段名称).

当您的调试器停在那里时,您可以检查Self.Name(Ctrl + F7),它会告诉您D4哪个是TGuid的第四个字段.这是因为JsonReflect通过序列化其字段来递归序列化记录.因为D4它声明array[0..7] of Byte它不包含类型信息(另见).

要解决此问题,请创建自己的类型拦截器TGUID:

type
  TGuidInterceptor = class(TJSONInterceptor)
  public
    function StringConverter(Data: TObject; Field: string): string; override;
    procedure StringReverter(Data: TObject; Field: string; Arg: string); override;
  end;

function TGuidInterceptor.StringConverter(Data: TObject;
  Field: string): string;
var
  ctx: TRttiContext;
begin
  Result := ctx.GetType(Data.ClassInfo).GetField(Field).GetValue(Data).AsType<TGuid>.ToString;
end;

procedure TGuidInterceptor.StringReverter(Data: TObject; Field, Arg: string);
var
  ctx: TRttiContext;
begin
  ctx.GetType(Data.ClassInfo).GetField(Field).SetValue(Data, TValue.From(TGuid.Create(Arg)));
end;
Run Code Online (Sandbox Code Playgroud)

并相应地标记该字段:

[JsonReflect(ctString, rtString, TGuidInterceptor)]
FID: TGUID;
Run Code Online (Sandbox Code Playgroud)