1. 为什么我们需要JSON助手如果你用过Delphi原生的JSON操作库肯定对那一长串的AddPair、GetValue、TryGetValue记忆犹新。每次操作JSON都要写一堆重复代码一个简单的赋值操作可能要写三四行。我在实际项目中就遇到过这种情况一个包含嵌套结构的JSON对象光是初始化代码就写了上百行看得人头皮发麻。Delphi从XE6版本开始原生支持JSON操作这个设计确实很完善但用起来实在太啰嗦。比如要给一个JSON对象添加字符串属性原生写法是这样的var jo: TJSONObject; begin jo : TJSONObject.Create; try jo.AddPair(name, TJSONString.Create(张三)); // 更多操作... finally jo.Free; end; end;而用我们封装的JSON助手同样的操作只需要一行jo.S[name] : 张三;这种简洁不是偷懒而是实实在在提升开发效率。我在维护一个老项目时把原来用SuperObject写的JSON操作全部迁移到了原生库代码量直接减少了40%。特别是处理复杂嵌套结构时这种简洁语法的优势更加明显。2. 助手的核心设计思路2.1 类助手的魔法这个JSON助手的核心是利用了Delphi的类助手(Class Helper)特性。类助手可以给现有类添加新的方法和属性就像给这个类打补丁一样。我们给TJSONObject添加了一系列快捷访问属性type TJSONObjectHelper class helper for TJSONObject public property S[PairName: string]: string read Get_ValueS write Set_ValueS; property I[PairName: string]: integer read Get_ValueI write Set_ValueI; // 其他属性... end;每个属性都对应着getter和setter方法内部处理了类型转换、空值判断等细节。比如S属性对应的setter是这样的procedure TJSONObjectHelper.Set_ValueS(PairName, PairValue: string); var js: TJSONString; begin if Self.TryGetValue(PairName, js) then Self.RemovePair(PairName).Free; Self.AddPair(PairName, PairValue); end;这个设计有几个巧妙之处自动处理已有键值如果键已存在会先删除旧值内存管理记得Free被替换掉的对象避免内存泄漏空值安全所有getter都处理了键不存在的情况2.2 支持的数据类型助手目前支持了开发中最常用的几种数据类型S[]字符串类型对应TJSONStringI[]整数类型对应TJSONNumber的整型值I64[]Int64大整数D[]日期时间存储为TJSONNumber的Double值B[]布尔值对应TJSONBoolA[]数组对应TJSONArrayO[]子对象对应TJSONObject这个设计覆盖了90%以上的JSON使用场景。我在实际项目中还扩展过一些特殊类型比如专门处理GUID的G[]属性原理都是一样的。3. 实际应用场景示例3.1 基本CRUD操作让我们看一个完整的增删改查示例。假设我们要处理一个用户信息JSONvar user: TJSONObject; begin user : TJSONObject.Create; try // 增 user.S[name] : 李四; user.I[age] : 30; user.B[isVIP] : True; // 改 user.I[age] : 31; // 修改年龄 // 查 if user.Exists[name] then ShowMessage(user.S[name]); // 删 user.Delete[isVIP]; // 输出最终JSON Memo1.Lines.Text : user.Format; finally user.Free; end; end;输出结果会是{ name: 李四, age: 31 }这种写法比原生API简洁多了而且可读性更好。我在团队推广这个助手后新人上手JSON操作的速度明显加快。3.2 处理嵌套结构JSON的嵌套结构用原生API写起来特别繁琐用助手就简单多了。比如要构建这样的结构{ user: { name: 王五, address: { city: 北京, street: 中关村 } } }用助手可以这样写var root: TJSONObject; begin root : TJSONObject.Create; try root.O[user] : TJSONObject.Create; root.O[user].S[name] : 王五; root.O[user].O[address] : TJSONObject.Create; root.O[user].O[address].S[city] : 北京; root.O[user].O[address].S[street] : 中关村; ShowMessage(root.Format); finally root.Free; end; end;虽然还是要创建每个嵌套对象但至少属性赋值变得非常直观。我在处理复杂API返回数据时这种写法节省了大量时间。4. 高级技巧与注意事项4.1 日期处理的坑JSON标准没有专门的日期类型我们通常用字符串或数字表示日期。助手提供了D[]属性来自动转换TDateTime// 写入日期 jo.D[birthday] : Now; // 读取日期 birthday : jo.D[birthday];但这里有个细节要注意日期是以Double值存储的相当于TDateTime的内部表示。如果你需要和其他系统交互可能需要手动转换为字符串格式// 写入格式化日期 jo.S[birthday] : FormatDateTime(yyyy-mm-dd, Now); // 读取时转换 birthday : StrToDate(jo.S[birthday]);我在一次跨系统集成中就踩过这个坑前端期望的是yyyy-mm-dd格式的字符串而我们直接传了Double值导致解析出错。4.2 内存管理最佳实践虽然助手简化了操作但内存管理还是要特别注意所有创建的TJSONObject和TJSONArray最终都要Free使用try-finally块确保资源释放修改属性值时助手会自动Free旧值数组和对象类型的属性不会自动Free传入的值特别提醒最后一点这样的代码会导致内存泄漏var arr: TJSONArray; begin arr : TJSONArray.Create; jo.A[items] : arr; // 忘记Free arr end;正确做法是让JSON对象接管生命周期jo.A[items] : TJSONArray.Create; // 由jo负责释放或者显式管理var arr: TJSONArray; begin arr : TJSONArray.Create; try jo.A[items] : arr; except arr.Free; raise; end; end;我在代码审查中发现这是最常见的错误之一建议团队统一采用第一种简写方式。4.3 性能优化建议在处理大型JSON数据时有几个性能优化点预分配大数组如果知道数组大概大小可以先创建指定大小的TJSONArray批量操作多次修改可以考虑先转成字符串用字符串操作再转回JSON避免频繁查询如果需要多次访问同一属性可以先用局部变量缓存例如处理包含1000个元素的数组// 不推荐 - 每次都要通过属性访问 for i : 0 to 999 do arr.Add(jo.A[items].Items[i].Value); // 推荐 - 缓存数组引用 items : jo.A[items]; for i : 0 to 999 do arr.Add(items.Items[i].Value);在性能测试中第二种写法能快20%左右。对于服务端高频处理的JSON数据这种优化还是很可观的。