You can use Utf8JsonReader.TryGetInt64(out long value)
and Utf8JsonReader.TryGetDecimal(out decimal value)
to test to see whether the current value can be successfully parsed as a long
or a decimal
.
Thus your modified Read()
method should look like:
public override IDictionary<string, object> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
// Assert we are currently at the beginning of an object
if (reader.TokenType != JsonTokenType.StartObject)
throw new JsonException(string.Format("Unexpected token {0}", reader.TokenType));
IDictionary<string, object> output = new Dictionary<string, object>();
while (reader.Read() && reader.TokenType != JsonTokenType.EndObject)
{
string propertyName = reader.GetString()!;
reader.Read();
object? propertyValue;
switch (reader.TokenType)
{
case JsonTokenType.Number:
if (reader.TryGetInt64(out var l))
propertyValue = l;
else if (reader.TryGetDecimal(out var d))
propertyValue = d;
else
{
// Either store the value as a string, or throw an exception.
using var doc = JsonDocument.ParseValue(ref reader);
propertyValue = doc.RootElement.ToString();
throw new JsonException(string.Format("Cannot parse number: {0}", propertyValue));
}
break;
case JsonTokenType.String:
if (reader.TryGetDateTime(out var dt))
propertyValue = dt;
else
propertyValue = reader.GetString();
break;
case JsonTokenType.True:
case JsonTokenType.False:
propertyValue = reader.GetBoolean();
break;
case JsonTokenType.Null:
propertyValue = null;
break;
default:
// An unexpected token type such as an object or array.
// You must either skip it or throw an exception.
reader.Skip();
propertyValue = null;
throw new JsonException(string.Format("Unexpected token {0}", reader.TokenType));
//break;
}
// Since your converter is of type IDictionary<string, object> I assume you don't want to allow null values.
// If you do want to allow null values you should declare it as IDictionary<string, object?>
if (propertyValue == null)
throw new JsonException("null value");
output.Add(propertyName, propertyValue);
}
return output;
}
Notes:
While Utf8JsonReader
will throw an exception on malformed JSON, it is the responsibility of the converter to handle any type of valid value token, and throw an exception on any unsupported value type.
I modified the converter to throw exceptions for unexpected value types as needed.
Since you seem to have enabled nullable reference type checking, I modified your code to throw an exception if propertyValue
is null. If you want to allow null property values you should declare your converter as a JsonConverter<IDictionary<string, object?>>
.
Your converter only handles primitive values. If you wanted to extend it to deserialize nested objects to nested Dictionary<string, object>
values, and nested arrays to nested List<object>
values, you could look at ObjectAsPrimitiveConverter
from this answer to C# - Deserializing nested json to nested Dictionary<string, object>.
Demo fiddle here.