You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#使用Json.NET:序列化忽略属性,按类型将content反序列到指定属性

刚好做过类似的需求,用Newtonsoft.Json的自定义转换器就能完美解决!我给你详细说下实现步骤和代码:

解决方案:自定义JsonConverter实现条件映射

要实现「序列化忽略RelationshipContent/DomainContent,反序列化时根据ContentTypecontent映射到对应属性」的需求,最直接的方式是写一个针对Foo类的自定义JsonConverter,完全掌控序列化和反序列化的逻辑。

1. 编写自定义转换器

这个转换器会负责:

  • 反序列化时:读取JSON中的contentType,把content字段转成对应的RelationshipDomains实例,赋值给Foo的对应属性
  • 序列化时:只输出需要的idcontentType,以及根据已有属性值生成的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类型,只需要在ReadJsonWriteJson里添加对应的分支即可
  • 序列化时会自动忽略[JsonIgnore]标记的RelationshipContentDomainContent,完全符合你的需求

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

火山引擎 最新活动