如何使用System.Text.Json向JsonElement添加新属性?

44u64gxh  于 2023-06-25  发布在  其他
关注(0)|答案(1)|浏览(272)

假设我有Dictionary<string,object>元。对象可以是JsonElement(System.Text.Json)
如果对象是一个元素数组,我需要迭代每个元素,并为每个元素添加新的属性。
我可以像这样迭代元素:

var metaValue = metas["key-1"];

if (metaValue is JsonElement elementValue && elementValue.ValueKind == JsonValueKind.Array)
 {
    // Iterate over the elements in the array
    foreach (var element in elementValue.EnumerateArray())
    {
        // add new property to element
        // like element["newproperty"] = "test value"
    }
 }

我的问题是,如何添加新的属性到JsonElement?

xienkqul

xienkqul1#

你不能修改JsonElement,它是完全不可变的。相反,您必须将其反序列化为某个可变类型,如JsonNode,修改可变类型,然后重新序列化回JsonElement。下面的方法可以做到这一点:

public static class JsonExtensions
{
    public static JsonNode TryAddPropertyToArrayElements<TProperty>(this JsonNode node, string name, TProperty value)
    {
        if (node is JsonArray array)
            foreach (var obj in array.OfType<JsonObject>())
                obj[name] = JsonSerializer.SerializeToNode(value);
        return node;
    }

    public static JsonElement TryAddPropertyToArrayElements<TProperty>(this JsonElement element, string name, TProperty value) =>
        element.ValueKind == JsonValueKind.Array
        ? JsonSerializer.SerializeToElement(JsonSerializer.Deserialize<JsonNode>(element)!.TryAddPropertyToArrayElements(name, value))
        : element;

    public static object? TryAddPropertyToArrayElements<TProperty>(this object? obj, string name, TProperty value) =>
        obj switch
        {
            JsonElement e => e.TryAddPropertyToArrayElements(name, value),
            JsonNode n => n.TryAddPropertyToArrayElements(name, value),
            null => null, // JSON values that are null are deserialized to the c# null value, not some element or node of type null
            _ => throw new ArgumentException("Unexpected type ${obj}"),
        };
}

那么您将使用它如下:

metas["key-1"] = metas["key-1"]?
    .TryAddPropertyToArrayElements("newproperty", "test value");

演示小提琴#1 here
显然,所有这些序列化都有些低效。为了避免额外的序列化,假设通过反序列化生成字典,可以使用JsonSerializerOptions.UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode进行反序列化。此设置强制声明为object的类型被反序列化为JsonNode而不是JsonElement

var inputOptions = new JsonSerializerOptions
{
    UnknownTypeHandling = JsonUnknownTypeHandling.JsonNode,
};
var metas = JsonSerializer.Deserialize<Dictionary<string, object?>>(json, inputOptions)!;

如果你这样做,你将能够使用上面包含的方法JsonExtensions.TryAddPropertyToArrayElements<TProperty>(this JsonNode node, string name, TProperty value)直接改变它的值。
注意事项:

  • JsonNodeJsonSerializer.SerializeToElement()是在.NET 6中引入的,因此如果您使用的是早期版本,则需要使用不同的方法。

演示小提琴#2 here

相关问题