考虑这两个JSON:
{
"name": "John",
"age": 40
}
和
{
"name": "John",
"age": "40"
}
唯一的区别是,在一种情况下,40
是一个数字,在另一种情况中,它是一个字符串。
我需要使用System.Text.Json
解析这些JSON,但我的代码失败了:
System.InvalidOperationException:无法将令牌类型"Number"的值作为字符串获取。
我反序列化JSON,然后使用JsonElement.GetString()
获取值。
我该怎么解决这个问题?
如果您有一个JsonElement
,那么您可以使用它的ValueKind
属性来确定它所代表的json的类型。
因此,例如,如果您解析了一个JsonDocument
并检索了它的RootElement
,那么JsonElement
的ValueKind
可以是Array
或Object
。
如果通过调用GetProperty
得到JsonElement
,则返回的JsonElement
的ValueKind
可以是任何预定义的值。
在您的特定示例中,您可以使用ValueKind
来根据提取的属性的数据类型确定应调用哪个GetXYZ
方法。
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;
}
}
上面的代码有点脆弱,因为如果ValueKind
是Number
,我就选择了GetInt32
。但是,如果你不知道数字的数据类型,那么你应该使用TryGetXYZ
方法来尝试以安全的方式获取数字。
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;
}
}