如何使用Json.NET反序列化高精度十进制值?

时间:2016-08-10 05:30:16

标签: c# json json.net deserialization json-deserialization

我想将包含长十进制值的JSON反序列化为自定义类型以保持其精度(即自定义BigDecimal类)。我使用的是Json.NET 9.0.1和.NET 4.6.1。我尝试过使用JsonConverter,但看起来调用ReadJson时可用的值已经被Json.NET识别并读取为.NET十进制类型,并且仅限于其精度。

理想情况下,我可以访问原始字符串,因此我可以将其置于自定义类型中。我可以在目标对象上使用字符串属性,并对完整字符串进行反序列化,但是我必须进一步处理该对象(即将其复制到另一个表示中),并且在大型模式中特别麻烦

有关更好方法的任何想法吗?

这是目标类:

public class DecimalTest
{
    public string stringValue { get; set; }
    public decimal decimalValue { get; set; }
    public BigDecimal bigDecimalValue { get; set; }
}

这是一个使用JSON的测试:

    [TestMethod]
    public void ReadBigDecimal_Test()
    {
        var json = @"{
            ""stringValue"" : 0.0050000012852251529693603515625,
            ""decimalValue"" : 0.0050000012852251529693603515625,
            ""bigDecimalValue"" : 0.0050000012852251529693603515625
        }";

        var settings = new JsonSerializerSettings();
        settings.FloatParseHandling = FloatParseHandling.Decimal;
        settings.Converters.Add(new JsonBigDecimalConverter());

        var result = JsonConvert.DeserializeObject<DecimalTest>(json, settings);

        Assert.IsNotNull(result);
        Assert.AreEqual("0.0050000012852251529693603515625", result.stringValue);
        Assert.AreEqual(0.0050000012852251529693603516m, result.decimalValue);

        // *** This case fails ***
        Assert.AreEqual("0.0050000012852251529693603515625", result.bigDecimalValue.ToString());
    }

这是自定义转换器:

public class JsonBigDecimalConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return (objectType == typeof(BigDecimal));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // *** reader.Value here already appears to be a .NET decimal.
        // *** If I had access to the raw string I could get this to work.
        return BigDecimal.Parse(reader.Value.ToString());
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

1 个答案:

答案 0 :(得分:1)

您是否可以尝试ReadJson的以下实现按预期工作:

public override object ReadJson(
    JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var token = JToken.Load(reader);
    return BigDecimal.Parse(token.ToString());
}

<强>更新

不幸的是,上面的工作没有成功。似乎没有办法从JSON数据中读取原始字符串。

另请注意,在我的测试中,stringValue的断言首先失败。请参阅此工作示例:https://dotnetfiddle.net/s0pqg3

我认为这是因为Json.NET内部会立即根据指定的number解析它遇到的任何FloatParseHandling令牌。原始数据永远不会被保留。

我认为唯一的解决方案是将大十进制字符串用引号括起来:

"bigDecimalValue" : "0.0050000012852251529693603515625"

这是一个完整的工作示例,以保持所需的精度:https://dotnetfiddle.net/U1UG3z