skip to Main Content

I am getting some data from an api that returns an object that has a property of Type Dictionary<int, double?>? in JSON. The issue is that some times the JSON will pass back Infinity in the double property so my deserialize fails trying to convert Infinity to double. I am trying to write a JsonConverter to handle this but I dont know how to check if the double is Infinity. This is what I have so far.

internal class InfinityDictionaryToNullJsonConverter : JsonConverter<Dictionary<int, double?>?>
{
    public override Dictionary<int, double?>? Read(ref Utf8JsonReader reader, Type typeToConvert,JsonSerializerOptions options)
    {
        if (reader.TokenType == JsonTokenType.StartObject)
        {
            Type keyType = typeToConvert.GetGenericArguments()[0];
            Type valueType = typeToConvert.GetGenericArguments()[1];

            if (reader.GetString().Contains("Infinity"))
            {
                return new Dictionary<int, double?> { { 0, 0 } };
            }
        }
        else
        {
            var test = reader.GetString();
        }

        return new Dictionary<int, double?> { { 0, 0 } };
    }

    public override void Write(Utf8JsonWriter writer,Dictionary<int, double?>? value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString());
    }
}

I can see that the reader.TokenType is JsonTokenType.StartObject but the next step is what I need help with. I would like to check if the double is Infinity, and if it is set it to default(double?) or even just 0.

An example of the data is here:

{
  "TeamRanks": {
    "0": "Infinity",
    "1": "1757.739122974623"
  }
}

3

Answers


  1. the easiest way is

    json = json.Replace(""Infinity"", "null");
    
    //or
    json = json.Replace(""Infinity"", """+ default(double).ToString()+""");  // "0"
    
    Login or Signup to reply.
  2. You can directly parse "Infinity, -Infinity, Nan" to double using the following overload of parse:

    Double.Parse(reader.GetString(), System.Globalization.CultureInfo.InvariantCulture);
    
    Login or Signup to reply.
  3. There is no need for a converter. You may deserialize that JSON by setting NumberHandling to JsonNumberHandling.AllowNamedFloatingPointLiterals and JsonNumberHandling.AllowReadingFromString:

    var options = new JsonSerializerOptions
    {
        NumberHandling = 
            JsonNumberHandling.AllowNamedFloatingPointLiterals 
            | JsonNumberHandling.AllowReadingFromString,
    };
    var model = JsonSerializer.Deserialize<Model>(json, options);
    

    As explained in the docs, this flag has the following possible values:

    Flag Meaning
    Strict [The default.] Numbers will only be read from Number tokens and will only be written as JSON numbers (without quotes).
    AllowNamedFloatingPointLiterals The "NaN", "Infinity", and "-Infinity" String tokens can be read as floating-point constants, and the Single and Double values for these constants will be written as their corresponding JSON string representations.
    AllowReadingFromString Numbers can be read from String tokens. Does not prevent numbers from being read from Number token.
    WriteAsString Numbers will be written as JSON strings (with quotes), not as JSON numbers.

    If you would prefer to replace the Infinity values with null you could do that in an IJsonOnDeserialized callback:

    public class Model : IJsonOnDeserialized
    {
        public Dictionary<int, double?>? TeamRanks { get; set; } = new ();
        
        public void OnDeserialized()
        {
            if (TeamRanks != null)
                foreach (var pair in TeamRanks.Where(p => p.Value != null && !double.IsFinite(p.Value.Value)).ToList())
                    TeamRanks[pair.Key] = null;
        }
    }
    

    However, Double.PositiveInfinity is a perfectly valid value for a c# double that can be checked for directly or by using !Double.IsFinite(value) so you might just leave the values as-is.

    Demo fiddle here.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search