我正在与System.Text.Json
在我的项目中,因为我正在处理大文件,所以也决定使用它来处理 GraphQL 响应。
由于 GraphQL 的性质,有时我会得到高度嵌套的响应,这些响应不固定,并且映射到类没有意义。我通常需要检查响应的一些属性。
我的问题是JsonElement
。检查嵌套属性感觉非常笨拙,我觉得应该有更好的方法来解决这个问题。
例如,采用下面的代码来模拟我得到的响应。我只想检查是否存在 2 个属性(id 和originalSrc)以及它们是否确实获得了它们的值,但感觉就像我已经吃了一顿代码。有没有更好/更清晰/更简洁的方式来写这个?
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
}
这并不是大量的代码,但检查一些属性非常常见,我想要一种更清晰、更易读的方法。
您可以添加几个访问子项的扩展方法JsonElement
value 按属性名称或数组索引,如果未找到则返回可为 null 的值:
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;
// Throw if index < 0
return index < element.GetArrayLength() ? element[index] : null;
}
}
现在,可以使用 null 条件运算符将访问嵌套值的调用链接在一起?. https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-:
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.
Notes:
-
如果传入元素不是预期类型(对象或数组或 null/缺失),上面的扩展方法将引发异常。你可以放松对ValueKind https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement.valuekind?view=netcore-3.1#System_Text_Json_JsonElement_ValueKind如果您不想在意外值类型上出现异常。
-
有开放 API 增强请求将 JsonPath 支持添加到 JsonDocument/JsonElement #31068 https://github.com/dotnet/runtime/issues/31068。查询通过JSONPath https://www.newtonsoft.com/json/help/html/QueryJsonSelectTokenJsonPath.htm如果实施的话,将使此类事情变得更容易。
-
如果您从 Newtonsoft 移植代码,请注意JObject
回报null
对于丢失的财产,同时JArray
抛出索引越界。因此您可能想使用JElement https://learn.microsoft.com/en-us/dotnet/api/system.text.json.jsonelement.item?view=net-5.0#System_Text_Json_JsonElement_Item_System_Int32_当尝试模拟 Newtonsoft 的行为时,直接使用数组索引器,如下所示,因为它也会引发索引越界:
var node = doc.Get("data")?.Get("products")?.Get("edges")?[0].Get("node");
演示小提琴here https://dotnetfiddle.net/3QVH6C.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)