带有消息 'Insufficient RTTi available to support this operation' 的 EInsufficientRTTI 异常
EInsufficientRTTI exception with message 'Insufficient RTTi available to support this operation'
尝试在 运行 时将对象转换为 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;
稍后在代码中:
var fpacket: TMYPacket;
begin
fpacket := TVWTCPPacket.create;
//assign value to class properties
memo1.Lines.Text := TJson.ObjectToJsonString(fpacket); //throws error
并在 JSON 转换时出现错误。
有人知道 Delphi Berlin 10.1 出了什么问题吗?
我确实记得 XE2 上的一些 RTTI 问题,但不确定上面发生的事情是否与 Delphi 旧错误有关。
进入System.Rtti
并在TRttiField.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;
并相应地标记字段:
[JsonReflect(ctString, rtString, TGuidInterceptor)]
FID: TGUID;
TGUID
种字段没有生成 RTTI。
因此,为了序列化您的 class,您可以只使用 getter/setter 函数,它设置一个字符串 属性.
类似于:
TMyPacket = class(TObject)
Private
FIDValue: TGUID;
FToIP: string;
FToPort: integer;
FSent: boolean;
FSentAt: TDateTime;
FAck: boolean;
FTimeOut: Cardinal;
FDataToSendSize: UINT64;
FDataToSend: AnsiString;
procedure SetID(const value: string);
function GetID: string;
public
constructor create;
destructor free;
property IDValue: TGUID read FID write FID;
published
property ID: string read GetID write SetID;
property ToIP: string read FToIP write FToIP;
property ToPort: integer read FToPort write FToPort
...
procedure TMyPacket.SetID(const value: string);
begin
fIDValue := StringToGUID(value);
end;
function TMyPacket.GetID: string;
begin
result := GUIDToString(fIDValue);
end;
然后序列化应该可以工作,使用 "ID":
字符串字段,您将在 IVValue
public 属性 中获得 TGUID
值。
检查dpr文件中是否存在这一行,如果存在则必须将其删除
{$IFOPT D-}{$WEAKLINKRTTI ON}{$ENDIF}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}
尝试在 运行 时将对象转换为 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;
稍后在代码中:
var fpacket: TMYPacket;
begin
fpacket := TVWTCPPacket.create;
//assign value to class properties
memo1.Lines.Text := TJson.ObjectToJsonString(fpacket); //throws error
并在 JSON 转换时出现错误。 有人知道 Delphi Berlin 10.1 出了什么问题吗? 我确实记得 XE2 上的一些 RTTI 问题,但不确定上面发生的事情是否与 Delphi 旧错误有关。
进入System.Rtti
并在TRttiField.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;
并相应地标记字段:
[JsonReflect(ctString, rtString, TGuidInterceptor)]
FID: TGUID;
TGUID
种字段没有生成 RTTI。
因此,为了序列化您的 class,您可以只使用 getter/setter 函数,它设置一个字符串 属性.
类似于:
TMyPacket = class(TObject)
Private
FIDValue: TGUID;
FToIP: string;
FToPort: integer;
FSent: boolean;
FSentAt: TDateTime;
FAck: boolean;
FTimeOut: Cardinal;
FDataToSendSize: UINT64;
FDataToSend: AnsiString;
procedure SetID(const value: string);
function GetID: string;
public
constructor create;
destructor free;
property IDValue: TGUID read FID write FID;
published
property ID: string read GetID write SetID;
property ToIP: string read FToIP write FToIP;
property ToPort: integer read FToPort write FToPort
...
procedure TMyPacket.SetID(const value: string);
begin
fIDValue := StringToGUID(value);
end;
function TMyPacket.GetID: string;
begin
result := GUIDToString(fIDValue);
end;
然后序列化应该可以工作,使用 "ID":
字符串字段,您将在 IVValue
public 属性 中获得 TGUID
值。
检查dpr文件中是否存在这一行,如果存在则必须将其删除
{$IFOPT D-}{$WEAKLINKRTTI ON}{$ENDIF}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}