1. 为什么我们需要重新封装System.JSON?
在Delphi开发中处理JSON数据已经成为日常需求,但官方提供的System.JSON单元虽然功能完整,API设计却显得过于底层和繁琐。想象一下,每次访问一个JSON属性都需要写GetValue('name').Value这样的链式调用,不仅代码冗长,还容易因为拼写错误导致运行时异常。
我曾在实际项目中遇到过这样的场景:需要从一个API返回的JSON中提取多层嵌套的数据,使用原生System.JSON的代码就像下面这样:
delphi复制var
LJsonObj: TJSONObject;
begin
LJsonObj := TJSONObject.ParseJSONValue(ResponseText) as TJSONObject;
try
UserName := LJsonObj.GetValue('data').GetValue('user').GetValue('name').Value;
UserAge := StrToInt(LJsonObj.GetValue('data').GetValue('user').GetValue('age').Value);
finally
LJsonObj.Free;
end;
end;
这样的代码不仅难以阅读和维护,还隐藏着多个潜在崩溃点——任何一级GetValue如果找不到对应的键都会返回nil,接着调用Value属性就会引发访问冲突。而一个设计良好的封装库应该能让我们这样写:
delphi复制var
LJson: TSimpleJson;
begin
LJson := TSimpleJson.Parse(ResponseText);
try
UserName := LJson['data.user.name'].AsString;
UserAge := LJson['data.user.age'].AsInteger;
finally
LJson.Free;
end;
end;
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心API设计与实现原理
2.1 链式属性访问设计
实现类似LJson['data.user.name']这样的链式访问,关键在于重载TSimpleJson类的[]操作符。核心代码如下:
delphi复制function TSimpleJson.GetItem(const Path: string): TSimpleJsonValue;
var
LNames: TArray<string>;
LCurrent: TJSONValue;
I: Integer;
begin
LNames := Path.Split(['.']);
LCurrent := FJsonValue; // FJsonValue是内部封装的TJSONValue
for I := 0 to High(LNames) do
begin
if not (LCurrent is TJSONObject) then
Exit(nil); // 或者抛出特定异常
LCurrent := (LCurrent as TJSONObject).GetValue(LNames[I]);
if LCurrent = nil then
Exit(nil);
end;
Result := TSimpleJsonValue.Create(LCurrent);
end;
这种实现方式有几个关键点:
- 使用Split方法将路径字符串按点号分割
- 逐级向下查找JSON节点
- 在任何一级查找失败时返回nil或抛出异常(取决于设计选择)
- 最终返回一个封装过的TSimpleJsonValue对象
2.2 类型安全转换处理
原生System.JSON中,所有值都以字符串形式存储,需要开发者手动转换。我们的封装库应该提供类型安全的访问方式:
delphi复制type
TSimpleJsonValue = class
private
FValue: TJSONValue;
public
function AsString: string;
function AsInteger: Integer;
functio
