使用 System.Text.Json 获取嵌套属性 [英] Getting nested properties with System.Text.Json
问题描述
我正在我的项目中使用 System.Text.Json
,因为我正在处理大文件,因此也决定使用它来处理 GraphQL 响应.
I am working with System.Text.Json
in my project as I am processing large files so also decided to use it for processing GraphQL responses.
由于 GraphQL 的性质,有时我会得到高度嵌套的响应,这些响应不固定并且映射到类没有意义.我通常需要检查响应的一些属性.
Due to the nature of GraphQL sometimes I get highly nested responses that are not fixed and don't make sense to map to a class. I usually need to check a few properties on the response.
我的问题是 JsonElement
.检查嵌套属性感觉很笨拙,我觉得应该有更好的方法来解决这个问题.
My issue is with JsonElement
. To check nested properties feels very clumsy and I feel like there should be a better way to approach this.
例如,下面的代码模拟了我得到的响应.我只想检查是否存在 2 个属性(id & originalSrc),以及它们是否确实获得了它们的值,但感觉就像我对代码做了一顿饭.有没有更好/更清晰/更简洁的方式来写这个?
For example take my below code simulating a response I get. I just want to check if 2 properties exist (id & originalSrc) and if they do get their value but it feels like I have made a meal of the code. Is there a better/clearer/more succinct way to write this?
var raw = @"{
""data"": {
""products"": {
""edges"": [
{
""node"": {
""id"": ""gid://shopify/Product/4534543543316"",
""featuredImage"": {
""originalSrc"": ""https://cdn.shopify.com/s/files/1/0286/pic.jpg"",
""id"": ""gid://shopify/ProductImage/146345345339732""
}
}
}
]
}
}
}";
var doc = JsonSerializer.Deserialize<JsonElement>(raw);
JsonElement node = new JsonElement();
string productIdString = null;
if (doc.TryGetProperty("data", out var data))
if (data.TryGetProperty("products", out var products))
if (products.TryGetProperty("edges", out var edges))
if (edges.EnumerateArray().FirstOrDefault().ValueKind != JsonValueKind.Undefined && edges.EnumerateArray().First().TryGetProperty("node", out node))
if (node.TryGetProperty("id", out var productId))
productIdString = productId.GetString();
string originalSrcString = null;
if(node.ValueKind != JsonValueKind.Undefined && node.TryGetProperty("featuredImage", out var featuredImage))
if (featuredImage.TryGetProperty("originalSrc", out var originalSrc))
originalSrcString = originalSrc.GetString();
if (!string.IsNullOrEmpty(productIdString))
{
//do stuff
}
if (!string.IsNullOrEmpty(originalSrcString))
{
//do stuff
}
这不是大量的代码,但检查一些属性是如此普遍,我想要一种更清晰、更易读的方法.
It is not a crazy amount of code but checking a handful of properties is so common I would like a cleaner more readble approach.
推荐答案
您可以添加几个扩展方法,通过属性名称或数组索引访问子 JsonElement
值,如果未找到:
You could add a couple of extension methods that access a child JsonElement
value by property name or array index, returning a nullable value if not found:
public static partial class JsonExtensions
{
public static JsonElement? Get(this JsonElement element, string name) =>
element.ValueKind != JsonValueKind.Null && element.ValueKind != JsonValueKind.Undefined && element.TryGetProperty(name, out var value)
? value : (JsonElement?)null;
public static JsonElement? Get(this JsonElement element, int index)
{
if (element.ValueKind == JsonValueKind.Null || element.ValueKind == JsonValueKind.Undefined)
return null;
var value = element.EnumerateArray().ElementAtOrDefault(index);
return value.ValueKind != JsonValueKind.Undefined ? value : (JsonElement?)null;
}
}
现在可以使用空条件运算符将访问嵌套值的调用链接在一起 ?.
:
Now calls to access nested values can be chained together using the null-conditional operator ?.
:
var doc = JsonSerializer.Deserialize<JsonElement>(raw);
var node = doc.Get("data")?.Get("products")?.Get("edges")?.Get(0)?.Get("node");
var productIdString = node?.Get("id")?.GetString();
var originalSrcString = node?.Get("featuredImage")?.Get("originalSrc")?.GetString();
Int64? someIntegerValue = node?.Get("Size")?.GetInt64(); // You could use "var" here also, I used Int64? to make the inferred type explicit.
注意事项:
如果传入的元素不是预期的类型(对象或数组或空/缺失),上述扩展方法将抛出异常.您可以放松对
ValueKind
如果您从不希望出现意外值类型的异常.
The extension methods above will throw an exception if the incoming element is not of the expected type (object or array or null/missing). You could loosen the checks on
ValueKind
if you never want an exception on an unexpected value type.
有一个开放的 API 增强请求 为 JsonDocument/JsonElement 添加 JsonPath 支持#31068.通过 JSONPath 进行查询(如果实施)将使此类事情变得更容易.
There is an open API enhancement request Add JsonPath support to JsonDocument/JsonElement #31068. Querying via JSONPath, if implemented, would make this sort of thing easier.
演示小提琴 此处.
这篇关于使用 System.Text.Json 获取嵌套属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!