C#使用Json.NET:序列化忽略属性,按类型将content反序列到指定属性
刚好做过类似的需求,用Newtonsoft.Json的自定义转换器就能完美解决!我给你详细说下实现步骤和代码:
解决方案:自定义JsonConverter实现条件映射
要实现「序列化忽略RelationshipContent/DomainContent,反序列化时根据ContentType把content映射到对应属性」的需求,最直接的方式是写一个针对Foo类的自定义JsonConverter,完全掌控序列化和反序列化的逻辑。
1. 编写自定义转换器
这个转换器会负责:
- 反序列化时:读取JSON中的
contentType,把content字段转成对应的Relationship或Domains实例,赋值给Foo的对应属性 - 序列化时:只输出需要的
id、contentType,以及根据已有属性值生成的content字段,自动忽略带[JsonIgnore]的属性
public class FooConverter : JsonConverter<Foo> { public override Foo ReadJson(JsonReader reader, Type objectType, Foo existingValue, bool hasExistingValue, JsonSerializer serializer) { // 把JSON加载成JObject,方便读取各个字段 var jsonObject = JObject.Load(reader); var fooInstance = new Foo(); // 先处理基础属性 fooInstance.Id = jsonObject["id"].Value<int>(); fooInstance.ContentType = jsonObject["contentType"].ToObject<object>(serializer); // 根据ContentType判断要把content反序列化成哪个类型 var contentType = fooInstance.ContentType?.ToString(); var contentToken = jsonObject["content"]; if (contentToken != null && contentToken.Type != JTokenType.Null) { // 这里替换成你实际业务中ContentType的取值,比如如果是枚举可以直接转枚举判断 if (contentType.Equals("Relationship", StringComparison.OrdinalIgnoreCase)) { fooInstance.RelationshipContent = contentToken.ToObject<Relationship>(serializer); } else if (contentType.Equals("Domain", StringComparison.OrdinalIgnoreCase)) { fooInstance.DomainContent = contentToken.ToObject<Domains>(serializer); } // 可以继续添加更多ContentType的分支逻辑 } return fooInstance; } public override void WriteJson(JsonWriter writer, Foo value, JsonSerializer serializer) { var jsonObject = new JObject(); // 序列化需要对外暴露的属性 jsonObject.Add("id", value.Id); jsonObject.Add("contentType", JToken.FromObject(value.ContentType, serializer)); // 根据哪个属性有值,把对应的对象转成content输出 if (value.RelationshipContent != null) { jsonObject.Add("content", JToken.FromObject(value.RelationshipContent, serializer)); } else if (value.DomainContent != null) { jsonObject.Add("content", JToken.FromObject(value.DomainContent, serializer)); } jsonObject.WriteTo(writer); } }
2. 应用转换器的两种方式
方式一:直接在Foo类上标记特性
这种方式最省心,所有序列化/反序列化操作都会自动使用这个转换器:
[JsonConverter(typeof(FooConverter))] public class Foo { [JsonProperty("id")] public int Id { get; set; } [JsonProperty("contentType")] public object ContentType { get; set; } // 原来的Content属性可以标记为[JsonIgnore],因为转换器已经处理了content的映射 [JsonIgnore] public object Content { get; set; } [JsonIgnore] public Relationship RelationshipContent { get; set; } [JsonIgnore] public Domains DomainContent { get; set; } }
方式二:在序列化/反序列化时手动传入
如果不想全局生效,也可以在调用方法时指定转换器:
// 反序列化示例 string jsonInput = "{\"id\":1,\"contentType\":\"Relationship\",\"content\":{/* Relationship的JSON */}}"; Foo foo = JsonConvert.DeserializeObject<Foo>(jsonInput, new FooConverter()); // 序列化示例 string jsonOutput = JsonConvert.SerializeObject(foo, new FooConverter());
3. 注意事项
- 如果
ContentType是枚举类型,建议把fooInstance.ContentType转成枚举再判断,比字符串比较更安全 - 如果有更多的Content类型,只需要在
ReadJson和WriteJson里添加对应的分支即可 - 序列化时会自动忽略
[JsonIgnore]标记的RelationshipContent和DomainContent,完全符合你的需求
内容的提问来源于stack exchange,提问作者MarsRoverII




