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

C#如何使用System.Text.Json反序列化带动态属性名的JSON?

实现结论

这个需求完全可以实现,有两种常用的实现方案,按需选择即可。


方案1:字典中转(最简实现,无需自定义转换器)

适合只需要单次转换、不需要复用逻辑的场景,步骤最少:

  1. 先把动态结构的group_ids字段反序列化为Dictionary<string, List<string>>类型,键对应群组ID字符串,值对应权限字符串数组
  2. 手动遍历字典做类型转换,得到目标GroupPermission集合

代码示例

首先定义根实体类:

public class RootObject
{
    [JsonPropertyName("id")]
    public int Id { get; set; }

    [JsonPropertyName("authorization_ids")]
    public List<int> AuthorizationIds { get; set; } = [];

    [JsonPropertyName("karma_user_ids")]
    public List<int> KarmaUserIds { get; set; } = [];

    // 中转用的字典属性,反序列化时直接映射
    [JsonPropertyName("group_ids")]
    public Dictionary<string, List<string>> RawGroupIds { get; set; } = [];

    // 直接对外暴露转换完成的权限集合
    [JsonIgnore]
    public List<GroupPermission> GroupPermissions => RawGroupIds.Select(kv => new GroupPermission
    {
        GroupID = int.Parse(kv.Key),
        // 权限按位合并,忽略大小写匹配枚举值
        Permission = kv.Value.Aggregate(0, (current, permStr) => 
            current | (int)Enum.Parse<Permission>(permStr, ignoreCase: true))
    }).ToList();
}

// 给Permission枚举加默认值避免空值问题
[Flags]
public enum Permission
{
    None = 0,
    full = 1,
    read = 2,
    overview = 4,
    change = 8,
    create = 16
}

反序列化调用:

var root = JsonSerializer.Deserialize<RootObject>(yourJsonString);
// 直接获取转换完成的集合
var permissions = root.GroupPermissions;

方案2:自定义JsonConverter(可复用,实体更干净)

适合多处用到该转换逻辑、希望实体类没有冗余属性的场景:

  1. 实现JsonConverter<List<GroupPermission>>,在读取JSON时直接解析动态键值对转换为目标集合
  2. 在根类的group_ids属性上标记使用该转换器即可

代码示例

首先实现自定义转换器:

public class GroupPermissionListConverter : JsonConverter<List<GroupPermission>>
{
    public override List<GroupPermission> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        using var jsonDoc = JsonDocument.ParseValue(ref reader);
        var rootEle = jsonDoc.RootElement;
        if (rootEle.ValueKind != JsonValueKind.Object)
            throw new JsonException("group_ids字段必须为对象类型");

        var result = new List<GroupPermission>();
        // 遍历所有动态属性(群组ID键)
        foreach (var prop in rootEle.EnumerateObject())
        {
            if (!int.TryParse(prop.Name, out var groupId))
                throw new JsonException($"无效的群组ID:{prop.Name}");

            Permission perm = Permission.None;
            // 遍历权限数组合并权限
            foreach (var permEle in prop.Value.EnumerateArray())
            {
                if (Enum.TryParse<Permission>(permEle.GetString(), ignoreCase: true, out var parsedPerm))
                {
                    perm |= parsedPerm;
                }
                // 未知权限可以在这里加处理逻辑,比如抛异常/打日志/忽略
            }

            result.Add(new GroupPermission { GroupID = groupId, Permission = perm });
        }
        return result;
    }

    // 如果需要序列化回原JSON结构就实现该方法,不需要可以直接抛NotImplementedException
    public override void Write(Utf8JsonWriter writer, List<GroupPermission> value, JsonSerializerOptions options)
    {
        writer.WriteStartObject();
        foreach (var gp in value)
        {
            writer.WritePropertyName(gp.GroupID.ToString());
            writer.WriteStartArray();
            foreach (Permission perm in Enum.GetValues(typeof(Permission)))
            {
                if (perm != Permission.None && gp.Permission.HasFlag(perm))
                {
                    writer.WriteStringValue(perm.ToString());
                }
            }
            writer.WriteEndArray();
        }
        writer.WriteEndObject();
    }
}

然后定义根实体类:

public class RootObject
{
    [JsonPropertyName("id")]
    public int Id { get; set; }

    [JsonPropertyName("authorization_ids")]
    public List<int> AuthorizationIds { get; set; } = [];

    [JsonPropertyName("karma_user_ids")]
    public List<int> KarmaUserIds { get; set; } = [];

    // 直接用目标类型,标记使用自定义转换器
    [JsonPropertyName("group_ids")]
    [JsonConverter(typeof(GroupPermissionListConverter))]
    public List<GroupPermission> GroupPermissions { get; set; } = [];
}

反序列化调用:

var root = JsonSerializer.Deserialize<RootObject>(yourJsonString);
// 直接使用root.GroupPermissions即可

注意事项

  • 如果权限字符串有和枚举名称不匹配的情况,可以在Enum.Parse处加异常处理或者自定义映射逻辑
  • 两种方案都兼容System.Text.Json原生的反序列化规则,不需要额外引入第三方库

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 11:54:04