Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

converting problems between doubles and strings in Newtonsoft.Json.net

Tags:

c#

json.net

I have updated my Newtonsoft.Json version from "8.0.3" to "9.0.1", After the change, I started to face some converting problems between doubles and strings.

Here's some code:

    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);
    }

In Newtonsoft.Json version "8.0.3" - the output of the class would be: Key - "test" Value - "210001" // No .0

In Newtonsoft.Json version "9.0.1" the output of the class would be Key - "test" Value - "210001.0"

This happens only when the value is 210001.0 - for 210001.1 it would not happen. Now I understand that the new version solves this problem better, but I have lot's of external code that depends on the old version solution. How can I achieve the old versions solution?

like image 396
oleg chernyakov Avatar asked Sep 20 '16 11:09

oleg chernyakov


People also ask

Is Newtonsoft JSON obsolete?

Yet Newtonsoft. Json was basically scrapped by Microsoft with the coming of . NET Core 3.0 in favor of its newer offering designed for better performance, System. Text.

Is System text JSON faster than Newtonsoft JSON?

As can be seen above, the System. Text. Json is much faster than the Newtonsoft. Json.

Is JObject parse slow?

That being said, it's known that parsing to JObject can be slower than deserializing -- see stackify.com/top-11-json-performance-usage-tips which states, Parsing generic JSON to a JSON.net JObject ... is slower (~20%) than reading that data in to a defined class type.

Which is better Newtonsoft JSON or System text JSON?

Json does case-insensitive property name matching by default. The System. Text. Json default is case-sensitive, which gives better performance since it's doing an exact match.


1 Answers

Solution which will definitely work is applying custom JsonConverter to the property, which will give you the control over how value is serialized/deserialized.

First step is creating a new JsonConverter, which is quite simple in implementation. I just invoke ToString() on the value, which can be either a decimal or 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);
    }
}

I made it so it can work with both values of FloatParseHandling and it will format the values as I presented in my previous, incorrect answer. You can of course tweak it to your liking, if you want it to ignore the FloatParseHandling but it will need type-checking to do it.

Just remember, that default value of FloatParseHandling is FloatParseHandling.Double, so it will work correctly without changing the serializer settings.

What you need to do next is mark the property with appropriate attribute so serializer will know to use it.

[JsonConverter(typeof(FloatStringConverter))]
public string Value { get; set; }

After this, Value will contain the correct representation of number from JSON.

like image 196
kiziu Avatar answered Oct 06 '22 01:10

kiziu