如何解决多类型Value字段的JSON反序列化与重新序列化问题?
这个问题我太熟悉了!用object来存这种动态类型的Value字段,确实会在重新序列化时丢失原始的JSON结构信息——尤其是像field3这种嵌套对象,很容易被序列化成一堆键值对的字典格式,而不是原来的嵌套JSON。下面给你几个实用的解决办法,根据你用的JSON库来选就行:
方案1:用JsonElement(适配System.Text.Json)
如果你用的是.NET Core/.NET 5+自带的System.Text.Json,直接把Value的类型改成JsonElement就行,它能完美保留原始的JSON结构,反序列化和重新序列化都不会出问题:
using System.Text.Json.Serialization; public class CustomField { [JsonPropertyName("definition")] public string Definition { get; set; } [JsonPropertyName("value")] public JsonElement Value { get; set; } } public class RootObject { [JsonPropertyName("id")] public string Id { get; set; } [JsonPropertyName("custom_fields")] public List<CustomField> CustomFields { get; set; } }
使用的时候也很简单,反序列化后如果需要读取具体的Value值,可以用JsonElement的类型判断方法,比如:
// 读取field1的字符串值 var field1Value = customFields.First(f => f.Definition == "field1").Value.GetString(); // 读取field3的嵌套对象id var field3UserId = customFields.First(f => f.Definition == "field3").Value.GetProperty("id").GetString();
重新序列化的时候,直接调用JsonSerializer.Serialize就能输出和原始JSON完全一致的结构。
方案2:用JToken(适配Newtonsoft.Json)
如果你项目里用的是Newtonsoft.Json(Json.NET),那把Value改成JToken是最省心的选择,它是Newtonsoft用来表示任意JSON元素的抽象类型,同样能完整保留原始结构:
using Newtonsoft.Json; public class CustomField { [JsonProperty("definition")] public string Definition { get; set; } [JsonProperty("value")] public JToken Value { get; set; } } public class RootObject { [JsonProperty("id")] public string Id { get; set; } [JsonProperty("custom_fields")] public List<CustomField> CustomFields { get; set; } }
读取具体值的示例:
// 读取field2的数组 var field2Values = customFields.First(f => f.Definition == "field2").Value.ToObject<List<string>>(); // 读取field3的嵌套对象 var field3User = customFields.First(f => f.Definition == "field3").Value.ToObject<User>();
重新序列化时,JToken会自动输出正确的JSON结构,完全不用担心嵌套对象的问题。
方案3:自定义转换器+强类型模型(适合需要类型安全的场景)
如果你希望代码有更强的类型约束,不想用JsonElement或JToken这种弱类型,可以自定义一个JSON转换器,根据definition字段来决定Value的类型。比如先定义几个可能的Value类型:
public class StringValue { public string Value { get; set; } } public class ArrayValue { public List<string> Value { get; set; } } public class UserValue { public User Value { get; set; } } public class User { public string Type { get; set; } public string Id { get; set; } }
然后写一个自定义转换器继承JsonConverter<object>(或者针对CustomField的转换器),在反序列化时根据definition来解析对应的Value类型,序列化时再反向处理。不过这个方案相对复杂一些,适合对类型安全要求很高的场景。
为什么用object会出问题?
本质原因是:反序列化时,JSON里的嵌套对象会被默认转换成JsonElement(System.Text.Json)或JObject(Newtonsoft),但当你把它们存在object类型的属性里,重新序列化时,序列化器无法识别它们原本的JSON结构,会把它们当成普通的.NET对象来序列化,比如把JObject序列化成字典格式,导致输出的JSON和原始结构不一致。
内容的提问来源于stack exchange,提问作者Wim Rijken

