定制json序列化

Posted 我思故我在

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了定制json序列化相关的知识,希望对你有一定的参考价值。

最近有人问我怎么定制一个json序列化,使序列化的时候只写出声明的父类成员,而不要把实际子类的成员写出来。当然,序列化用的是大家用的最多的json.net。

简单的说,这是个契约怎么解析的问题,json.net选择使用实际类型自然是有多方面的考量,毕竟申明类型可以是抽象类或接口等。废话不说了,直接上代码(仅用于示例,要用于生产的话需要处理各种边缘情况)。

  1. 类型关系

    public class RootObj
    {
        public A A { get; set; }
    }
    
    public class A
    {
        public string X { get; set; }
    }
    
    public class B : A
    {
        public string Y { get; set; }
    }
  2. 实例和序列化

    var r = new RootObj { A = new B { X = "x", Y = "y" } };
    Console.WriteLine(JsonConvert.SerializeObject(r));
    在什么都不改的情况下,输出是:
    {"A":{"Y":"y","X":"x"}}
    而期望值是:
    {"A":{"X":"x"}}
    我们期望只输出A的成员。
  3. 写自己的JsonConverter:

    public class JC<T> : JsonConverter
    {
        public override bool CanConvert(Type objectType) => throw new NotImplementedException();
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) => throw new NotImplementedException();
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            writer.WriteStartObject();
            var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(typeof(T));
            foreach (var prop in contract.Properties)
            {
                writer.WritePropertyName(prop.PropertyName);
                serializer.Serialize(writer, prop.ValueProvider.GetValue(value));
            }
            writer.WriteEndObject();
        }
    }
  4. 标记我们的类型

    public class RootObj
    {
        [JsonConverter(typeof(JC<A>))]
        public A A { get; set; }
    }
  5. Run! 然后就可以发现结果和我们期待的一样了:)

源代码传输门

以上是关于定制json序列化的主要内容,如果未能解决你的问题,请参考以下文章

Go 定制JSON序列化

json序列化时定制支持datetime类型,和到中文让他保留中文形式

Sublime Text自定制代码片段(Code Snippets)

golang的xorm如何将[]map[string][]byte 格式的数据序列化成json输出

@JSONField的使用

定制序列化之@JSONType的使用