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?
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.
As can be seen above, the System. Text. Json is much faster than the Newtonsoft. Json.
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With