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

咨询mORMot/Synopse JSON未知元素默认值的优雅实现方案

我完全懂你对mORMot/Synopse JSON实现的偏爱——那种像访问对象属性一样用.直接获取JSON元素的语法,在封装基于单个Variant状态的对象时,真的把代码的简洁性和直观性拉满了。针对你遇到的「JSON元素不存在时返回默认值」的需求,同时避开NullStrictConvert的全局副作用和重复的空值判断代码,这里有几个实用的解决方案:

方案1:通用辅助函数(最易实现)

写一个全局的辅助函数,专门处理JSON字段的空值判断与默认值返回,所有getter都复用这个函数,彻底消除重复代码:

function GetJSONFieldOrDefault(const AJson: Variant; const AFieldName: string; const ADefault: Variant): Variant;
begin
  // 用下标访问字段,和点语法效果一致,但更适合动态字段名场景
  Result := AJson[AFieldName];
  // 若字段不存在或为Null,返回默认值
  if VarIsNull(Result) then
    Result := ADefault;
end;

然后在你的对象getter里这样用:

function TMyObject.GetName: String;
begin
  Result := GetJSONFieldOrDefault(FState, 'name', '');
end;

// 其他字段示例,比如整数类型
function TMyObject.GetAge: Integer;
begin
  Result := GetJSONFieldOrDefault(FState, 'age', 0);
end;

这个方案的优势是无额外依赖、兼容性强,不管你用的是Delphi还是Free Pascal,都能直接跑,而且只需要写一次辅助函数,后续所有字段都能复用。

方案2:Variant Helper类(更优雅的语法)

如果你想让代码看起来更像原生方法,可以给Variant写一个Helper类,扩展出获取默认值的方法:

unit VariantJSONHelpers;

interface

uses
  SysUtils, Variants;

type
  TVariantJSONHelper = class helper for Variant
  public
    function GetFieldOrDefault(const AFieldName: string; const ADefault: Variant): Variant;
    // 针对常用类型写重载,进一步简化代码
    function GetStringOrDefault(const AFieldName: string; const ADefault: string = ''): string;
    function GetIntegerOrDefault(const AFieldName: string; const ADefault: Integer = 0): Integer;
  end;

implementation

function TVariantJSONHelper.GetFieldOrDefault(const AFieldName: string; const ADefault: Variant): Variant;
begin
  Result := Self[AFieldName];
  if VarIsNull(Result) then
    Result := ADefault;
end;

function TVariantJSONHelper.GetStringOrDefault(const AFieldName: string; const ADefault: string = ''): string;
begin
  Result := GetFieldOrDefault(AFieldName, ADefault);
end;

function TVariantJSONHelper.GetIntegerOrDefault(const AFieldName: string; const ADefault: Integer = 0): Integer;
begin
  Result := GetFieldOrDefault(AFieldName, ADefault);
end;

end.

使用时就像调用Variant的原生方法一样简洁:

function TMyObject.GetName: String;
begin
  Result := FState.GetStringOrDefault('name');
end;

function TMyObject.GetAge: Integer;
begin
  Result := FState.GetIntegerOrDefault('age');
end;

这种方式让代码更具可读性,而且针对常用类型的重载可以省去手动传默认值的麻烦,适合长期维护的项目。

方案3:利用mORMot内置工具函数

mORMot框架本身其实提供了一些JSON操作的辅助函数,比如JSONGet(需确认你使用的版本是否包含),它可以直接指定默认值:

function TMyObject.GetName: String;
begin
  Result := JSONGet(FState, 'name', '');
end;

如果你的mORMot版本支持这个函数,那这就是最轻量化的方案——不需要自己写任何辅助代码,直接用框架原生能力解决问题。

关键注意点

  • 所有方案都不会影响全局状态,完全避开了NullStrictConvert的线程安全问题和全局副作用;
  • 不管用哪种方案,都只需要写一次通用逻辑,后续字段无需重复编写空值判断;
  • 这些实现都是线程安全的,因为仅针对单个Variant实例进行处理,没有共享的全局变量。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 20:47:55