C#如何使用System.Text.Json反序列化带动态属性名的JSON?
实现结论
这个需求完全可以实现,有两种常用的实现方案,按需选择即可。
方案1:字典中转(最简实现,无需自定义转换器)
适合只需要单次转换、不需要复用逻辑的场景,步骤最少:
- 先把动态结构的
group_ids字段反序列化为Dictionary<string, List<string>>类型,键对应群组ID字符串,值对应权限字符串数组 - 手动遍历字典做类型转换,得到目标
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(可复用,实体更干净)
适合多处用到该转换逻辑、希望实体类没有冗余属性的场景:
- 实现
JsonConverter<List<GroupPermission>>,在读取JSON时直接解析动态键值对转换为目标集合 - 在根类的
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
相关产品推荐
相关产品推荐

