在Newtonsoft.Json.net中转换双打和字符串之间的问题

时间:2016-09-20 11:51:03

标签: c# json.net

我已将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,它不会发生。 现在我明白新版本可以更好地解决这个问题,但是我有很多外部代码依赖于旧版本的解决方案。 如何实现旧版本解决方案?

2 个答案:

答案 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

请参阅demo at dotnetfiddle.net

请注意,从Decimal更改为Double时,您可能会失去一些精确度。

编辑: 我已经将问题追溯到JsonTextReader.ReadStringValue的略微改变的实现。在版本8.0.3中,它使用数字类型作为中间类型,因此在从FloatParseHandlingfloat的反序列化期间使用了string。在版本9.0.1中,它不再使用数字类型,它只使用了JSON的子字符串并将其设置为值。

总而言之,我对JSON.net不够熟悉,不能在其他答案中提出除JsonConverter以外的任何其他选项。也许更熟悉它的人可以提供别的东西。

答案 1 :(得分:3)

确定有效的解决方案是将自定义JsonConverter应用于属性,这将使您可以控制值的序列化/反序列化方式。

第一步是创建一个新的JsonConverter,这在实现中非常简单。我只是在值上调用ToString(),可以是decimaldouble

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的正确数字表示。