如何在C#中对含字符串与对象的动态列表进行(De)Serialize并转为自定义对象?
在C#中处理混合类型列表的(De)Serialize
当然可以在C#中处理这种混合了字符串和对象的动态列表的序列化/反序列化!这种异构类型的JSON结构确实需要特殊处理,下面我会给出几种实用的实现方案,分别基于Newtonsoft.Json(Json.NET)和内置的System.Text.Json。
首先,我们先定义核心的Permission类,用来映射JSON中的对象结构:
public class Permission { public string PermissionName { get; set; } public string Namespace { get; set; } }
方案一:直接反序列化为混合类型列表再处理
如果只是临时处理这种混合结构,可以先把列表反序列化为List<object>或者dynamic,然后逐个判断元素类型并转换为Permission对象。这里以Newtonsoft.Json为例:
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; class Program { static void Main() { // 你的示例JSON string json = @" { ""permission"": [ ""Group1"", ""Group2"", { ""PermissionName"" : ""QA"", ""Namespace"" : ""Namespace1"" } ] }"; // 先反序列化为动态对象 var dynamicResult = JsonConvert.DeserializeObject<dynamic>(json); List<object> rawPermissions = dynamicResult.permission.ToObject<List<object>>(); // 转换为统一的Permission列表 List<Permission> permissions = new List<Permission>(); foreach (var item in rawPermissions) { if (item is string groupName) { // 字符串类型直接转为Permission,Namespace设为null/空 permissions.Add(new Permission { PermissionName = groupName }); } else if (item is JObject jObj) { // JObject类型直接反序列化为Permission permissions.Add(jObj.ToObject<Permission>()); } } // 输出结果验证 foreach (var p in permissions) { Console.WriteLine($"权限名称: {p.PermissionName}, 命名空间: {p.Namespace ?? "无"}"); } } }
方案二:自定义Json转换器(推荐)
如果需要长期处理这种结构,自定义Json转换器是更优雅的方式——它能自动完成字符串和对象之间的转换,让你直接反序列化为List<Permission>,序列化时也能保持原JSON的混合格式。
基于Newtonsoft.Json的转换器
using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; public class PermissionConverter : JsonConverter<Permission> { public override Permission ReadJson(JsonReader reader, Type objectType, Permission existingValue, bool hasExistingValue, JsonSerializer serializer) { // 处理字符串类型的元素 if (reader.TokenType == JsonToken.String) { return new Permission { PermissionName = (string)reader.Value }; } // 处理对象类型的元素 else if (reader.TokenType == JsonToken.StartObject) { JObject jObj = JObject.Load(reader); return jObj.ToObject<Permission>(); } throw new JsonException("无法识别的权限类型"); } public override void WriteJson(JsonWriter writer, Permission value, JsonSerializer serializer) { // 序列化时,如果Namespace为空,输出字符串;否则输出对象 if (string.IsNullOrEmpty(value.Namespace)) { writer.WriteValue(value.PermissionName); } else { serializer.Serialize(writer, value); } } } // 定义根对象类来匹配JSON结构 public class RootObject { [JsonProperty("permission")] public List<Permission> Permission { get; set; } } class Program { static void Main() { string json = @" { ""permission"": [ ""Group1"", ""Group2"", { ""PermissionName"" : ""QA"", ""Namespace"" : ""Namespace1"" } ] }"; // 配置序列化设置,添加自定义转换器 var settings = new JsonSerializerSettings(); settings.Converters.Add(new PermissionConverter()); // 直接反序列化为RootObject var result = JsonConvert.DeserializeObject<RootObject>(json, settings); // 验证反序列化结果 foreach (var p in result.Permission) { Console.WriteLine($"权限名称: {p.PermissionName}, 命名空间: {p.Namespace ?? "无"}"); } // 序列化回去,验证格式是否和原JSON一致 string serializedJson = JsonConvert.SerializeObject(result, Formatting.Indented, settings); Console.WriteLine("\n序列化后的JSON:"); Console.WriteLine(serializedJson); } }
基于System.Text.Json的转换器
如果你用的是.NET Core 3.0+或.NET 5+,可以直接用内置的System.Text.Json实现:
using System; using System.Collections.Generic; using System.Text.Json; using System.Text.Json.Serialization; public class PermissionConverter : JsonConverter<Permission> { public override Permission Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.String) { return new Permission { PermissionName = reader.GetString() }; } else if (reader.TokenType == JsonTokenType.StartObject) { return JsonSerializer.Deserialize<Permission>(ref reader, options); } throw new JsonException("无法识别的权限类型"); } public override void Write(Utf8JsonWriter writer, Permission value, JsonSerializerOptions options) { if (string.IsNullOrEmpty(value.Namespace)) { writer.WriteStringValue(value.PermissionName); } else { JsonSerializer.Serialize(writer, value, options); } } } public class RootObject { [JsonPropertyName("permission")] public List<Permission> Permission { get; set; } } class Program { static void Main() { string json = @" { ""permission"": [ ""Group1"", ""Group2"", { ""PermissionName"" : ""QA"", ""Namespace"" : ""Namespace1"" } ] }"; var options = new JsonSerializerOptions(); options.Converters.Add(new PermissionConverter()); options.WriteIndented = true; var result = JsonSerializer.Deserialize<RootObject>(json, options); foreach (var p in result.Permission) { Console.WriteLine($"权限名称: {p.PermissionName}, 命名空间: {p.Namespace ?? "无"}"); } string serializedJson = JsonSerializer.Serialize(result, options); Console.WriteLine("\n序列化后的JSON:"); Console.WriteLine(serializedJson); } }
总结
- 临时处理用方案一,快速灵活;
- 长期维护用方案二,代码更整洁,序列化/反序列化逻辑统一;
- 两种主流的JSON库都支持自定义转换器,根据你的项目环境选择即可。
内容的提问来源于stack exchange,提问作者crunchynutter
相关产品推荐
相关产品推荐

