NewtonSoft Json反序列化十进制数,超过8位小数

时间:2015-10-29 18:29:08

标签: json.net decimal deserialization

我得到以下json

"location": {
  "x": 3693779.702309093,
  "y": 500061.05750159378
}

以下课程

Class Location
    public property x as string
    public property y as string
end class

我需要使用所有小数位置对json进行反序列化 但是当我使用NewtonSoft Json进行反序列化时,它仅舍入到8位小数。

最初,我将类定义为x,y为小数,但我认为舍入是由数据类型引起的,这就是我改为字符串的原因。

但是,似乎实际的Json反序列化只用了8位小数。

任何想法如何使用所有小数来反序列化?

谢谢

2 个答案:

答案 0 :(得分:2)

您可能在Json.NET中发现了一个错误。将数值读入字符串时,首先将值解析为数值类型(doublelongBigInteger),然后将其转换为{{3}中的字符串}:

                string s;
                if (Value is IFormattable)
                    s = ((IFormattable)Value).ToString(null, Culture);
                else
                    s = Value.ToString();

                SetToken(JsonToken.String, s, false);
                return s;

问题似乎是JsonReader.ReadAsStringInternal()不使用往返精度,除非格式字符串明确指定为"G17"。相反,我使用

System.ComponentModel.TypeDescriptor.GetConverter(Value).ConvertToString(null, Culture, Value)

没有精确损失。

您可能希望Double.ToString(String, IFormatProvider)了解这一点。

有几种解决方法:

  1. 使用report an issue to NewtonSoft反序列化您的课程。在这种情况下,数值将暂时解析为decimal而不是double

  2. 编写一个将值加载到JValue的转换器,检查类型为JTokenType.Float的值,并返回正确的字符串:

    public class StringNumericConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return objectType == typeof(string);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (reader.TokenType == JsonToken.Null)
                return null;
            var value = JToken.Load(reader);
            if (value.Type == JTokenType.Float)
                return System.ComponentModel.TypeDescriptor.GetConverter(((JValue)value).Value).ConvertToInvariantString(((JValue)value).Value);
            return (string)value;
        }
    
        public override bool CanWrite { get { return false; } }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }
    

    或者在VB.NET中:

    Public Class StringNumericConverter
        Inherits JsonConverter
        Public Overrides Function CanConvert(objectType As Type) As Boolean
            Return objectType = GetType(String)
        End Function
    
        Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
            If reader.TokenType = JsonToken.Null Then
                Return Nothing
            End If
            Dim value = JToken.Load(reader)
            If value.Type = JTokenType.Float Then
                Return System.ComponentModel.TypeDescriptor.GetConverter(DirectCast(value, JValue).Value).ConvertToInvariantString(DirectCast(value, JValue).Value)
            End If
            Return CType(value, String)
        End Function
    
        Public Overrides ReadOnly Property CanWrite() As Boolean
            Get
                Return False
            End Get
        End Property
    
        Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
            Throw New NotImplementedException()
        End Sub
    End Class
    

    请注意,对于整数字符串,JValue.Value将是Int64JsonSerializerSettings.FloatParseHandling = FloatParseHandling.Decimal;你不能认为它会是双倍的。

    原型BigInteger

答案 1 :(得分:0)

我自己想出了解决方案。

首先我在

下面创建了转换器
public Class JsonGeometryConverter
  Inherits JsonConverter

  Public Overrides Function CanConvert(objectType As Type) As Boolean
    Return True
  End Function

  Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
    Dim valF As double = reader.Value
    Dim valFS = String.Format("{0:G17}", valF)
    Return valFS
  End Function

  Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
    Throw New NotImplementedException()
  End Sub
End Class

然后我将converter属性应用于属性以将值提取到

Public Class RestGIS_LocationInfo
  <JsonConverter(GetType(JsonGeometryConverter))>  
  Public Property X As string = ""

  <JsonConverter(GetType(JsonGeometryConverter))>  
  Public Property Y As String = ""
End Class

转换器将json数据中的实际值读取为double,并返回格式为最多17位精度的格式(有关详细信息,请参阅https://msdn.microsoft.com/en-us/library/kfsatb94.aspx