我已将Newtonsoft.Json版本从“8.0.3”更新为“9.0.1”, 改变之后,我开始面对双打和字符串之间的一些转换问题。
以下是一些代码:
public class KeyValue
{
public string Key { get; set; }
public string Value { get; set; }
}
private void button1_Click(object sender, EventArgs e)
{
var json = "{\"Key\": 'test', \"Value\": 210001.0}";
var kv = JsonConvert.DeserializeObject<KeyValue>(json);
}
在Newtonsoft.Json版本“8.0.3”中 - 该类的输出将是: 关键测试” 值 - “210001”// No .0
在Newtonsoft.Json版本“9.0.1”中,类的输出将是 关键测试” 价值 - “210001.0”
仅当值为210001.0时才会发生 - 对于210001.1,它不会发生。 现在我明白新版本可以更好地解决这个问题,但是我有很多外部代码依赖于旧版本的解决方案。 如何实现旧版本解决方案?
答案 0 :(得分:3)
这种情况发生了,因为显然Newtonsoft.Json
的作者更改了JsonSerializerSettings.FloatParseHandling
的默认值。这改变了字符串转换中使用的中间类型。 0
出现在字符串的末尾,因为反序列化程序使用Decimal
作为数字类型,当您尝试运行时
210001.0M.ToString()
你得到了
210001.0
要恢复为数字Double
的旧处理,您必须在反序列化时明确指定它,例如。
JsonConvert.DeserializeObject<KeyValue>(json, new JsonSerializerSettings { FloatParseHandling = FloatParseHandling.Double });
这会导致反序列化器将其作为
执行210001D.ToString()
返回
210001
请注意,从Decimal
更改为Double
时,您可能会失去一些精确度。
编辑:
我已经将问题追溯到JsonTextReader.ReadStringValue
的略微改变的实现。在版本8.0.3中,它使用数字类型作为中间类型,因此在从FloatParseHandling
到float
的反序列化期间使用了string
。在版本9.0.1中,它不再使用数字类型,它只使用了JSON的子字符串并将其设置为值。
总而言之,我对JSON.net不够熟悉,不能在其他答案中提出除JsonConverter
以外的任何其他选项。也许更熟悉它的人可以提供别的东西。
答案 1 :(得分:3)
确定有效的解决方案是将自定义JsonConverter
应用于属性,这将使您可以控制值的序列化/反序列化方式。
第一步是创建一个新的JsonConverter
,这在实现中非常简单。我只是在值上调用ToString()
,可以是decimal
或double
。
public sealed class FloatStringConverter : JsonConverter
{
public override bool CanWrite { get { return false; } }
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotSupportedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
return reader.Value.ToString();
}
public override bool CanConvert(Type objectType)
{
return objectType == typeof(double) || objectType == typeof(decimal);
}
}
我做了它,因此它可以使用FloatParseHandling
的两个值,它将格式化我在之前的错误答案中呈现的值。您当然可以根据自己的喜好进行调整,如果您希望它忽略FloatParseHandling
,但它需要进行类型检查才能完成。
请记住,FloatParseHandling
的默认值为FloatParseHandling.Double
,因此无需更改序列化设置即可正常工作。
接下来需要做的是使用适当的属性标记属性,以便序列化程序知道如何使用它。
[JsonConverter(typeof(FloatStringConverter))]
public string Value { get; set; }
在此之后,Value
将包含来自JSON的正确数字表示。