通过RTTI进行对象序列化不再起作用

时间:2017-02-20 17:02:58

标签: delphi rtti

我有2年的项目,我正在重新启动。我有调试窗口,显示不同的信息,其中一部分是序列化各种google protobuf对象并显示它们。

以下是典型protobuf类的外观:

// Generated by the protocol buffer compiler.  DO NOT EDIT!
// Source: message.proto
unit Poker.Protobufs.Objects.PingParams;

interface

uses
  System.SysUtils,
  {$IFNDEF FPC} System.Generics.Collections {$ELSE} Contnrs {$ENDIF},
  pbOutput, Poker.Protobufs.Objects.Base, Poker.Protobufs.Reader, Poker.Types;

type
  TPB_PingParams = class(TProtobufBaseObject)
  private
    const
      kUptimeFieldNumber = 1;

    var
      FUptime: UInt32;
      FHasBits: UINT32;

    procedure set_has_Uptime;
    procedure clear_has_Uptime;
    procedure SetUptime(const AValue: UInt32);
  public
    constructor Create(const AFrom: TPB_PingParams; const ALightweight: Boolean = FALSE); overload;
    destructor Destroy; override;
    procedure LoadFromProtobufReader(const AProtobufReader: TProtobufReader; const ASize: Integer); override;
    procedure MergeFrom(const AFrom: TPB_PingParams);
    procedure Clear;
    function IsInitialized: Boolean; override;

    // required uint32 Uptime = 1;
    function has_Uptime: Boolean;
    procedure clear_Uptime;
    property Uptime: UInt32 read FUptime write SetUptime;
  end;

  TPB_PingParamsList = class(TObjectList<TPB_PingParams>)
    procedure Assign(const APB_PingParamsList: TList<TPB_PingParams>);
  end;

implementation

uses
  pbPublic;


constructor TPB_PingParams.Create(const AFrom: TPB_PingParams; const ALightweight: Boolean = FALSE);
begin
  inherited Create(ALightweight);
  MergeFrom(AFrom);
end;

destructor TPB_PingParams.Destroy;
begin
  inherited;
end;

procedure TPB_PingParams.LoadFromProtobufReader(const AProtobufReader: TProtobufReader; const ASize: Integer);
var
  tag, field_number, wire_type, endpos: Integer;
begin
  endpos := AProtobufReader.getPos + ASize;
  while (AProtobufReader.getPos < endpos) and
        (AProtobufReader.GetNext(tag, wire_type, field_number)) do
    case field_number of
      kUptimeFieldNumber: begin
        Assert(wire_type = WIRETYPE_VARINT);
        FUptime := AProtobufReader.readUInt32;
        set_has_Uptime;
      end;
    else
      AProtobufReader.skipField(tag);
    end;
end;

procedure TPB_PingParams.MergeFrom(const AFrom: TPB_PingParams);
begin
  if AFrom.has_Uptime then
    SetUptime(AFrom.Uptime);
end;

function TPB_PingParams.IsInitialized: Boolean;
begin
  if (FHasBits and $1) <> $1 then
    Exit(FALSE);
  Exit(TRUE);
end;

procedure TPB_PingParams.clear_Uptime;
begin
  FUptime := 0;
  clear_has_Uptime;
end;

function TPB_PingParams.has_Uptime: Boolean;
begin
  result := (FHasBits and 1) > 0;
end;

procedure TPB_PingParams.set_has_Uptime;
begin
  FHasBits := FHasBits or 1;
end;

procedure TPB_PingParams.clear_has_Uptime;
begin
  FHasBits := FHasBits and not 1;
end;

procedure TPB_PingParams.SetUptime(const AValue: UInt32);
begin
  if not Lightweight then
    Assert(not has_Uptime);
  FUptime := AValue;
  if not Lightweight then
    ProtobufOutput.writeUInt32(kUptimeFieldNumber, AValue);
  set_has_Uptime;
end;

procedure TPB_PingParams.Clear;
begin
  if FHasBits = 0 then
    Exit;

  clear_Uptime;
end;

procedure TPB_PingParamsList.Assign(const APB_PingParamsList: TList<TPB_PingParams>);
var
  pbobj: TPB_PingParams;
begin
  Clear;
  for pbobj in APB_PingParamsList do
    Add(TPB_PingParams.Create(pbobj, TRUE));
end;

end. 

我的序列化功能:

function SerializeObject(const AObject: TObject): String;
var
  t: TRttiType;
  p: TRttiProperty;
  properties: TArray<TRttiProperty>;
  method: TRttiMethod;
begin
  result := '';
  if not Assigned(AObject) then
    Exit;

  t := TRttiContext.Create.GetType(AObject.ClassType);
  properties := t.GetProperties;
  for p in properties do
  begin
    method := t.GetMethod(Format('has_%s', [p.Name]));
    if (Assigned(method)) and
       (method.Invoke(AObject, []).AsBoolean) then
      result := result + Format('%s: %s; ', [p.Name, ValueToStr(p, p.GetValue(AObject))]);
  end;
end;

它专门用于序列化protobuf对象中以has_开头的字段。现在,我在过去的两年里没有对代码中的任何内容进行任何更改,而这在以前也有用。但现在却没有。行properties = t.GetProperties为我的protobuf类返回空数组。

我的猜测是我有一些全局定义的编译器指令,它允许我序列化类中的公共方法。但我无法弄清楚哪一个。

如果我将{$M+}放在我的protobuf课程前面,并将方法移至published,那么它有效(有点)。但这之前就像它在源中显示的那样有效,没有任何{$M+}指令或类似的。所以我很好奇我错过了什么。

编译器和以前一样,XE2。

0 个答案:

没有答案