Reputation: 2539
Consider these two JSONs:
{
"name": "John",
"age": 40
}
and
{
"name": "John",
"age": "40"
}
The only difference is that in one, 40
is a number, in the other it's a string.
I need to parse these JSONs using System.Text.Json
and my code fails:
System.InvalidOperationException : Cannot get the value of a token type 'Number' as a string.
I deserialize the JSON and then use JsonElement.GetString()
to get the values.
How can I fix this?
Upvotes: 1
Views: 1523
Reputation: 22714
If you have a JsonElement
then you can use its ValueKind
property to determine the type of the json which it represents.
So, for instance if you have parsed a JsonDocument
and you retrieve its RootElement
then that JsonElement
's ValueKind
can be either Array
or Object
.
If you have a JsonElement
by calling the GetProperty
then the returned JsonElement
's ValueKind
can be any of the predefined values.
In your particular example you can use the ValueKind
to determine which GetXYZ
method should be called based on the fetched property's data type.
string input1 = "{\"name\": \"John\", \"age\": 40}";
string input2 = "{\"name\": \"John\", \"age\": \"40\"}";
foreach (var input in new[] { input1, input2 })
{
var doc = JsonDocument.Parse(input);
var age = doc.RootElement.GetProperty("age");
switch (age.ValueKind)
{
case JsonValueKind.Number:
{
var value = age.GetInt32();
Console.WriteLine($"{value} as a number");
break;
}
case JsonValueKind.String:
{
var value = age.GetString();
Console.WriteLine($"{value} as a text");
break;
}
default:
Console.WriteLine("unknown type");
break;
}
}
The above code is a bit fragile, since I've picked GetInt32
if the ValueKind
is Number
.
But if you don't know upfront the number's data type then you should use the TryGetXYZ
methods to try to fetch numbers in a safe way.
string input1 = "{\"name\": \"John\", \"age\": 40}";
string input2 = "{\"name\": \"John\", \"age\": \"40\"}";
string input3 = "{\"name\": \"John\", \"age\": 40.0}";
foreach (var input in new[] { input1, input2, input3 })
{
var doc = JsonDocument.Parse(input);
var age = doc.RootElement.GetProperty("age");
switch (age.ValueKind)
{
case JsonValueKind.Number:
{
if(age.TryGetInt32(out var integralNumber))
Console.WriteLine($"{integralNumber} as an integral number");
else if (age.TryGetDouble(out var floatingNumber))
Console.WriteLine($"{floatingNumber} as a floating number");
break;
}
case JsonValueKind.String:
{
var value = age.GetString();
Console.WriteLine($"{value} as a text");
break;
}
default:
Console.WriteLine("unknown type");
break;
}
}
Upvotes: 2