You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi含短字符串的记录JSON序列化时字段丢失问题求解

Delphi XE 10.2.2中TJsonSerializer忽略短字符串(string[N])字段的解决方法

问题根源

你推测的没错,问题确实出在RTTI上。Delphi的System.Rtti单元对静态短字符串(string[N])的支持有限,TJsonSerializer在遍历RTTI字段时会默认跳过这类类型——因为它无法直接识别并处理静态长度的字符串结构,而AnsiString和String(UnicodeString)属于动态字符串类型,RTTI对其有完善支持,所以能正常序列化。

解决方法

方法1:批量替换短字符串类型(最直接)

如果项目允许修改现有字段定义,把所有string[N]替换为AnsiString或String是最快的解决方案:

// 原记录定义
type
  TMyRecord = record
    ShortStrField: string[50];
  end;

// 修改后
type
  TMyRecord = record
    ShortStrField: AnsiString; // 或直接用 String(UnicodeString)
  end;

这种方式无需额外编写序列化逻辑,直接复用TJsonSerializer的原生功能即可。

方法2:自定义RTTI扩展处理短字符串

如果无法修改字段类型,可以通过扩展RTTI和手动处理短字符串的方式实现序列化:

  1. 定义一个标记用的自定义属性(可选,也可直接通过类型判断):
uses
  System.Rtti;

type
  TShortStringAttr = class(TCustomAttribute);
  1. 给短字符串字段添加标记:
type
  TMyRecord = record
    [TShortStringAttr]
    ShortStrField: string[50];
    NormalField: String;
  end;
  1. 编写自定义序列化函数,手动读取短字符串内容:
uses
  System.JSON.Serializers, System.JSON, System.TypInfo;

function SerializeWithShortStrings(const ARecord: TValue): TJSONObject;
var
  RttiCtx: TRttiContext;
  RttiType: TRttiType;
  RttiField: TRttiField;
  ShortStrVal: string;
begin
  Result := TJSONObject.Create;
  RttiCtx := TRttiContext.Create;
  try
    RttiType := RttiCtx.GetType(ARecord.TypeInfo);
    for RttiField in RttiType.GetFields do
    begin
      // 判断字段是否为短字符串类型
      if (RttiField.FieldType.TypeKind = tkUString) and (RttiField.FieldType is TRttiOrdinalType) then
      begin
        // 手动读取短字符串内容
        ShortStrVal := StrPas(PAnsiChar(ARecord.GetReferenceToRawData + RttiField.Offset));
        Result.AddPair(RttiField.Name, TJSONString.Create(ShortStrVal));
      end
      else
      begin
        // 其他类型用默认序列化逻辑
        Result.AddPair(RttiField.Name, TJsonSerializer.Default.SerializeValue(RttiField.GetValue(ARecord)));
      end;
    end;
  finally
    RttiCtx.Free;
  end;
end;

使用时直接调用该函数代替默认序列化即可。

方法3:继承TJsonSerializer重写字段处理逻辑

如果想完全集成到TJsonSerializer的工作流中,可以继承它并重写字段处理方法:

type
  TCustomJsonSerializer = class(TJsonSerializer)
  protected
    procedure SerializeField(AObject: TObject; AField: TRttiField; AJsonPair: TJSONPair); override;
    procedure SerializeValue(const AValue: TValue; out AJsonValue: TJSONValue); override;
  end;

procedure TCustomJsonSerializer.SerializeField(AObject: TObject; AField: TRttiField; AJsonPair: TJSONPair);
var
  FieldVal: TValue;
  ShortStrVal: string;
begin
  FieldVal := AField.GetValue(AObject);
  if (AField.FieldType.TypeKind = tkUString) and (AField.FieldType is TRttiOrdinalType) then
  begin
    ShortStrVal := StrPas(PAnsiChar(FieldVal.GetReferenceToRawData));
    AJsonPair.JsonValue := TJSONString.Create(ShortStrVal);
  end
  else
  begin
    inherited;
  end;
end;

procedure TCustomJsonSerializer.SerializeValue(const AValue: TValue; out AJsonValue: TJSONValue);
var
  ShortStrVal: string;
begin
  if (AValue.TypeInfo.Kind = tkUString) and (AValue.TypeInfo is TRttiOrdinalType) then
  begin
    ShortStrVal := StrPas(PAnsiChar(AValue.GetReferenceToRawData));
    AJsonValue := TJSONString.Create(ShortStrVal);
  end
  else
  begin
    inherited;
  end;
end;

之后使用TCustomJsonSerializer替代默认的TJsonSerializer,即可自动处理短字符串字段。

内容的提问来源于stack exchange,提问作者Asa IL

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 19:10:20