.NET+RemObjects环境下,JSON序列化如何强制浮点字段保留末尾零?
实现Oxygene中Nullable字段JSON序列化保留至少两位小数
方案一:使用自定义JavaScriptConverter(原生JavaScriptSerializer)
由于System.Web.Script.Serialization.JavaScriptSerializer默认不会保留浮点数字的末尾零,我们可以通过实现自定义转换器来控制序列化逻辑。注意:JSON数字类型本身不区分小数位数,此方案会将浮点值转为字符串类型以保留两位小数格式。
1. 定义自定义转换器
MyTypeConverter = public class(System.Web.Script.Serialization.JavaScriptConverter) public method Serialize(obj: System.Object; serializer: System.Web.Script.Serialization.JavaScriptSerializer): System.Collections.Generic.IDictionary<string, System.Object>; override; method Deserialize(dictionary: System.Collections.Generic.IDictionary<string, System.Object>; type: System.Type; serializer: System.Web.Script.Serialization.JavaScriptSerializer): System.Object; override; method GetSupportedTypes(): System.Collections.Generic.IEnumerable<System.Type>; override; end; implementation method MyTypeConverter.GetSupportedTypes(): System.Collections.Generic.IEnumerable<System.Type>; begin Result := new List<System.Type>([typeof(MyType)]); end; method MyTypeConverter.Serialize(obj: System.Object; serializer: System.Web.Script.Serialization.JavaScriptSerializer): System.Collections.Generic.IDictionary<string, System.Object>; var myTypeObj: MyType; dict: Dictionary<string, Object>; begin myTypeObj := obj as MyType; dict := new Dictionary<string, Object>(); if myTypeObj.valueD.HasValue then // 格式化为两位小数的字符串 dict.Add('valueD', myTypeObj.valueD.Value.ToString("F2")) else dict.Add('valueD', null); Result := dict; end; method MyTypeConverter.Deserialize(dictionary: System.Collections.Generic.IDictionary<string, System.Object>; type: System.Type; serializer: System.Web.Script.Serialization.JavaScriptSerializer): System.Object; var myTypeObj: MyType; valueStr: string; valueD: Double; begin myTypeObj := new MyType(); if dictionary.ContainsKey('valueD') and (dictionary['valueD'] <> null) then begin valueStr := dictionary['valueD'] as string; if Double.TryParse(valueStr, valueD) then myTypeObj.valueD := valueD; end; Result := myTypeObj; end;
2. 使用转换器序列化
var data: MyType; s: string; serializer: System.Web.Script.Serialization.JavaScriptSerializer; begin data := new MyType; data.valueD := 1.9; serializer := new System.Web.Script.Serialization.JavaScriptSerializer(); serializer.Converters.Add(new MyTypeConverter()); s := serializer.Serialize(data); // 结果: {"valueD": "1.90"} end;
方案二:改用Newtonsoft.Json(输出数字类型的1.90)
如果需要保留数字类型同时显示两位小数格式,JavaScriptSerializer无法实现,建议使用功能更强大的Newtonsoft.Json库。
1. 定义自定义数字转换器
MyDoubleConverter = public class(Newtonsoft.Json.JsonConverter) public method CanConvert(objectType: Type): Boolean; override; method WriteJson(writer: Newtonsoft.Json.JsonWriter; value: Object; serializer: Newtonsoft.Json.JsonSerializer); override; method ReadJson(reader: Newtonsoft.Json.JsonReader; objectType: Type; existingValue: Object; serializer: Newtonsoft.Json.JsonSerializer): Object; override; end; implementation method MyDoubleConverter.CanConvert(objectType: Type): Boolean; begin Result := objectType = typeof(System.Nullable<Double>) or objectType = typeof(Double); end; method MyDoubleConverter.WriteJson(writer: Newtonsoft.Json.JsonWriter; value: Object; serializer: Newtonsoft.Json.JsonSerializer); var d: Double; begin if value = null then begin writer.WriteNull(); exit; end; d := Double(value); // 直接写入格式化后的数字字符串,保留两位小数 writer.WriteRawValue(d.ToString("F2")); end; method MyDoubleConverter.ReadJson(reader: Newtonsoft.Json.JsonReader; objectType: Type; existingValue: Object; serializer: Newtonsoft.Json.JsonSerializer): Object; var d: Double; begin if reader.Value = null then begin if objectType = typeof(System.Nullable<Double>) then Result := null else Result := 0.0; exit; end; Double.TryParse(reader.Value.ToString(), d); Result := d; end;
2. 序列化对象
var data: MyType; s: string; settings: Newtonsoft.Json.JsonSerializerSettings; begin data := new MyType; data.valueD := 1.9; settings := new Newtonsoft.Json.JsonSerializerSettings(); settings.Converters.Add(new MyDoubleConverter()); s := Newtonsoft.Json.JsonConvert.SerializeObject(data, settings); // 结果: {"valueD": 1.90} end;
关键说明
- JSON的数字类型本身不保留小数位数,
1.9和1.90在JSON语义中完全等价,解析后的值均为1.9。 - 若仅需输出字符串格式的两位小数,使用方案一;若需输出数字类型且显示两位小数,必须使用方案二这类支持自定义数字格式化的序列化库。
内容的提问来源于stack exchange,提问作者wBB
相关产品推荐
相关产品推荐

