You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中实现通用的反序列化JSON任意属性修改方法?

需求:通用修改JSON任意属性的C#方法

现有文件内容

config/data.json

{
    "background": false,
    "title": "XYZ",
    "object1": {
        "something1": -1,
        "something2": "auto",
        "something3": false,
        "something4": true
    },
    "object2": {
        "something1": true,
        "something2": true,
        "something3": false,
        "something4": [
            [5,0],
            [4,1]
        ]
    },
    "object3": [
        {
            "something1": null,
            "something2": null,
            "something3": "someString",
            "something4": "someString"
        }
    ]
}

program.cs 实体类定义

// JSON反序列化所需的类
public class Object1
{
    public int something1 { get; set; }
    public string something2 { get; set; }
    public bool something3 { get; set; }
    public bool something4 { get; set; }
}

public class Object2
{
    public bool something1 { get; set; }
    public bool something2 { get; set; }
    public bool something3 { get; set; }
    public IList<IList<int>> something4 { get; set; }
}

public class Object3
{
    public object something1 { get; set; }
    public object something2 { get; set; }
    public string something3 { get; set; }
    public string something4 { get; set; }
}

public class Example
{
    public bool background { get; set; }
    public string title { get; set; }
    public Object1 object1 { get; set; }
    public Object2 object2 { get; set; }
    public IList<Object3> object3 { get; set; }
}

现有处理方法

private readonly static string rigJsonPath = 
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, Path.Combine("config", "data.json"));

public static Example ReadAndDeserialize()
{ 
    string json = File.ReadAllText(rigJsonPath);
    Example ex = JsonSerializer.Deserialize<Rig.Xmrig>(json)!;
    return ex;   
}
public static void SerializeAndWrite(Example ex)
{
    string json = JsonSerializer.Serialize(ex);
    File.WriteAllText(rigJsonPath, json);
}
public static void ModifyXmrProperty(Example ex, string propertyName, object propertyValue)
{
    switch (propertyName)
    {
        case "background":
            ex.background = (bool)propertyValue;
            break;
        case "title":
            ex.title = (string)propertyValue;
            break;
        case "object1.something1":
            ex.object1!.something1 = (int)propertyValue;
            break;
           // 等等,但这种方式无法覆盖所有属性
    }
}

核心需求

需要实现一个通用方法,接收参数后完成「JSON反序列化 → 修改指定字段(支持任意层级属性、嵌套对象、数组元素) → 序列化回写覆盖文件」的完整流程,避免为每个属性编写switch分支。


解决方案

方案1:使用JsonNode(.NET 6+ 推荐)

JsonNode是System.Text.Json原生支持的动态JSON操作API,无需依赖强类型类即可灵活修改任意节点:

private readonly static string rigJsonPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "data.json");

public static void ModifyJsonProperty(string propertyPath, object propertyValue)
{
    // 读取并解析JSON为可操作节点
    string jsonContent = File.ReadAllText(rigJsonPath);
    JsonNode rootNode = JsonNode.Parse(jsonContent)!;

    // 拆分属性路径(如"object3[0].something3"拆分为["object3[0]", "something3"])
    string[] pathSegments = propertyPath.Split('.');
    JsonNode currentNode = rootNode;

    // 遍历路径定位到目标节点的父级
    for (int i = 0; i < pathSegments.Length - 1; i++)
    {
        string segment = pathSegments[i];
        if (segment.Contains('['))
        {
            // 处理数组索引,提取数组名和下标
            string arrayName = segment.Substring(0, segment.IndexOf('['));
            int index = int.Parse(segment.Substring(segment.IndexOf('[') + 1, segment.IndexOf(']') - segment.IndexOf('[') - 1));
            currentNode = currentNode[arrayName]![index];
        }
        else
        {
            currentNode = currentNode[segment]!;
        }
    }

    // 设置目标节点值
    string targetSegment = pathSegments[^1];
    if (targetSegment.Contains('['))
    {
        string arrayName = targetSegment.Substring(0, targetSegment.IndexOf('['));
        int index = int.Parse(segment.Substring(segment.IndexOf('[') + 1, segment.IndexOf(']') - segment.IndexOf('[') - 1));
        currentNode[arrayName]![index] = JsonValue.Create(propertyValue);
    }
    else
    {
        currentNode[targetSegment] = JsonValue.Create(propertyValue);
    }

    // 格式化后回写文件
    string updatedJson = rootNode.ToJsonString(new JsonSerializerOptions { WriteIndented = true });
    File.WriteAllText(rigJsonPath, updatedJson);
}

使用示例:

// 修改顶级布尔属性
ModifyJsonProperty("background", true);
// 修改嵌套对象的数值属性
ModifyJsonProperty("object1.something1", 100);
// 修改数组中对象的字符串属性
ModifyJsonProperty("object3[0].something3", "updatedString");
// 修改二维数组元素
ModifyJsonProperty("object2.something4[0][1]", 5);

方案2:反射处理强类型对象

如果必须基于已有的Example强类型类操作,可通过反射遍历属性路径:

private readonly static string rigJsonPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "config", "data.json");

public static void ModifyStrongTypeProperty(string propertyPath, object propertyValue)
{
    // 反序列化为强类型对象
    Example ex = ReadAndDeserialize();
    object currentObj = ex;
    Type currentType = typeof(Example);

    string[] pathSegments = propertyPath.Split('.');
    for (int i = 0; i < pathSegments.Length - 1; i++)
    {
        string segment = pathSegments[i];
        if (segment.Contains('['))
        {
            // 处理数组索引
            string arrayName = segment.Substring(0, segment.IndexOf('['));
            int index = int.Parse(segment.Substring(segment.IndexOf('[') + 1, segment.IndexOf(']') - segment.IndexOf('[') - 1));
            PropertyInfo arrayProp = currentType.GetProperty(arrayName)!;
            IList array = (IList)arrayProp.GetValue(currentObj)!;
            currentObj = array[index];
            currentType = currentObj.GetType();
        }
        else
        {
            // 遍历嵌套对象属性
            PropertyInfo prop = currentType.GetProperty(segment)!;
            currentObj = prop.GetValue(currentObj)!;
            currentType = prop.PropertyType;
        }
    }

    // 设置目标属性值(自动转换类型)
    string targetSegment = pathSegments[^1];
    if (targetSegment.Contains('['))
    {
        string arrayName = targetSegment.Substring(0, targetSegment.IndexOf('['));
        int index = int.Parse(segment.Substring(segment.IndexOf('[') + 1, segment.IndexOf(']') - segment.IndexOf('[') - 1));
        PropertyInfo arrayProp = currentType.GetProperty(arrayName)!;
        IList array = (IList)arrayProp.GetValue(currentObj)!;
        Type elementType = arrayProp.PropertyType.GetGenericArguments()[0];
        array[index] = Convert.ChangeType(propertyValue, elementType);
    }
    else
    {
        PropertyInfo targetProp = currentType.GetProperty(targetSegment)!;
        targetProp.SetValue(currentObj, Convert.ChangeType(propertyValue, targetProp.PropertyType));
    }

    // 回写文件
    SerializeAndWrite(ex);
}

// 修正原反序列化方法的泛型错误
public static Example ReadAndDeserialize()
{ 
    string json = File.ReadAllText(rigJsonPath);
    return JsonSerializer.Deserialize<Example>(json)!;   
}

使用示例:

ModifyStrongTypeProperty("title", "NewAppTitle");
ModifyStrongTypeProperty("object2.something3", true);
ModifyStrongTypeProperty("object3[0].something1", 456);

方案对比

  • JsonNode方案:无需强类型类,支持动态JSON结构修改,代码简洁,适合JSON结构可能变动的场景。
  • 反射方案:基于强类型实体,自带类型校验,适合JSON结构固定、需要强类型约束的场景。

内容的提问来源于stack exchange,提问作者Mikson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 10:29:52