如何在Delphi中反序列化C++ std::multimap生成的JSON至TDictionary<double,string>
在Delphi中用mORMot将数字键JSON对象反序列化为TDictionary<double, string>
针对你遇到的问题,这里提供两种可行的解决方案,分别适用于简单解析场景和复杂结构体自动反序列化场景:
方法1:手动遍历JSON对象键值对
这种方式直接高效,无需额外配置,适合单独解析目标JSON节点的场景:
uses SysUtils, Generics.Collections, mORMot.Json; function JsonObjToDoubleStringDict(const AJsonObj: TJSONObject): TDictionary<double, string>; var LPair: TJSONPair; LKey: double; begin Result := TDictionary<double, string>.Create; try for LPair in AJsonObj do begin if TryStrToFloat(LPair.JsonString.Value, LKey) then Result.Add(LKey, LPair.JsonValue.Value); end; except Result.Free; raise; end; end; // 使用示例 var LJson: TJSONValue; LSomeObj: TJSONObject; LDict: TDictionary<double, string>; begin LJson := TJSON.ParseJSONValue('{"name":"mark","data":[1,2,3,4],"some":{"11.1":"Hello","22.2":"","44.4":"World"}}'); try LSomeObj := LJson.GetValue<TJSONObject>('some'); LDict := JsonObjToDoubleStringDict(LSomeObj); try // 遍历输出字典内容示例 for var KVP in LDict do Writeln(Format('%.1f: %s', [KVP.Key, KVP.Value])); finally LDict.Free; end; finally LJson.Free; end; end;
方法2:注册mORMot自定义序列化器
如果需要在复杂结构体的自动反序列化中直接映射该类型,可以给TDictionary<double, string>注册自定义序列化逻辑:
uses SysUtils, Generics.Collections, mORMot, mORMot.Json, mORMot.Core.JSON; // 封装字典类型以便注册(mORMot对泛型类直接注册可能存在限制) type TDoubleStringDict = class(TDictionary<double, string>) end; // 注册自定义序列化/反序列化逻辑 procedure RegisterDoubleStringDictSerializer; begin TJSONSerializer.RegisterCustomSerializer(TDoubleStringDict, // 序列化逻辑(可选,若需要将字典转回JSON) procedure(const Obj: TObject; out Value: TJSONValue) var LDict: TDoubleStringDict; LObj: TJSONObject; KVP: TPair<double, string>; begin LDict := TDoubleStringDict(Obj); LObj := TJSONObject.Create; try for KVP in LDict do LObj.AddPair(FloatToStr(KVP.Key), KVP.Value); Value := LObj; except LObj.Free; raise; end; end, // 反序列化逻辑 procedure(const Value: TJSONValue; Obj: TObject) var LDict: TDoubleStringDict; LObj: TJSONObject; LPair: TJSONPair; LKey: double; begin LDict := TDoubleStringDict(Obj); LObj := Value as TJSONObject; LDict.Clear; for LPair in LObj do begin if TryStrToFloat(LPair.JsonString.Value, LKey) then LDict.Add(LKey, LPair.JsonValue.Value); end; end); end; // 定义对应完整结构体 type TMyData = class public name: string; data: TArray<integer>; some: TDoubleStringDict; constructor Create; destructor Destroy; override; end; constructor TMyData.Create; begin inherited; some := TDoubleStringDict.Create; end; destructor TMyData.Destroy; begin some.Free; inherited; end; // 使用示例 var LJsonStr: string; LMyData: TMyData; begin RegisterDoubleStringDictSerializer; LJsonStr := '{"name":"mark","data":[1,2,3,4],"some":{"11.1":"Hello","22.2":"","44.4":"World"}}'; LMyData := TJSONSerializer.JsonToObject<TMyData>(LJsonStr); try // 输出结构体中字典的内容 for var KVP in LMyData.some do Writeln(Format('Key: %.1f, Value: %s', [KVP.Key, KVP.Value])); finally LMyData.Free; end; end;
注意事项
- 由于JSON键本质是字符串,转换
double时需注意格式兼容性(如小数点分隔符,若需支持非英文区域可传入TFormatSettings参数); - 若原C++
std::multimap存在重复的double键,TDictionary无法存储重复键,此时需改用TList<TPair<double, string>>等支持重复键的结构,并调整对应解析逻辑。
内容的提问来源于stack exchange,提问作者ckok
相关产品推荐
相关产品推荐

