c# 通过json.net中的JsonConverter进行自定义序列化与反序列化
相信大家在工作中会经常遇见对json进行序列化与反序列化吧,但通常的序列化与反序列化中的json结构与c#中的类模型结构是相对应的,我们是否可以在序列化一个对象时候,让我们json的数据结构能按照自己的意愿,而不必与该对象的数据结构一样呢?,比如说,一个对象,只有一个名为"ID"的int类型的属性,值为1,如果序列化该对象,则能得到json:{"ID":1},但我现在希望得到的json的"ID"值是bool类型:{"ID":true}。要满足能够进行自定义序列化与反序列化的要求,我们可以运用json.net中的转换器JsonConverter。
先来个简单的例子,就上面那个,一个对象,只有一个名为"ID"的int类型的属性,值为1,序列化该对象,如果ID值为1,则能得到json:{"ID":true},如果ID值不为1,得到json{"ID":false}。
定义类:
public class Model { public int ID { get; set; } }
NuGet添加引用Newtonsoft.Json,再定义一个转换器类MyConverter,这个类要继承Newtonsoft.Json命名空间下的一个抽象类JsonConverter,我们先来看下这个抽象类的成员,有两个属性与三个抽象方法:
在MyConverter中我们要实现这三个抽象方法CanConvert()、ReadJson()、WriteJson(),并用特性[JsonConverter(typeof(MyConverter))]标记在我们要自定义序列化的类Model上就行了,就像这样:
[JsonConverter(typeof(MyConverter))] public class Model { public int ID { get; set; } }
在序列化Model对象的时候,程序会走到MyConverter下已经实现的WriteJson()方法,同理,反序列化会走到ReadJson()方法,而CanConvert方法是用于判断是否需要自定义序列化或者反序列化的,它的参数objectType对应着特性JsonConverter所标记类的对应Type类型。
下面是MyConverter类的代码实现:
public class MyConverter : JsonConverter { //是否开启自定义反序列化,值为true时,反序列化时会走ReadJson方法,值为false时,不走ReadJson方法,而是默认的反序列化 public override bool CanRead => false; //是否开启自定义序列化,值为true时,序列化时会走WriteJson方法,值为false时,不走WriteJson方法,而是默认的序列化 public override bool CanWrite => true; public override bool CanConvert(Type objectType) { return typeof(Model) == objectType; } 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) { //new一个JObject对象,JObject可以像操作对象来操作json var jobj = new JObject(); //value参数实际上是你要序列化的Model对象,所以此处直接强转 var model = value as Model; if (model.ID != 1) { //如果ID值为1,添加一个键位"ID",值为false jobj.Add("ID",false); } else { jobj.Add("ID", true); } //通过ToString()方法把JObject对象转换成json var jsonstr = jobj.ToString(); //调用该方法,把json放进去,最终序列化Model对象的json就是jsonstr,由此,我们就能自定义的序列化对象了 writer.WriteValue(jsonstr); } }
之后我们在Main函数里进行测试:
static void Main(string[] args) { var model = new Model(); model.ID = 1; var json = JsonConvert.SerializeObject(model);//由于ID值为1,得到json为{"ID":ture} Console.WriteLine(json); model.ID = 2; json = JsonConvert.SerializeObject(model);//由于ID值不为1,得到json为{"ID":false} Console.WriteLine(json); Console.ReadKey(); }
但是,还有一个问题,如果我们把json再反序列化为Model对象时会发生错误,因为json在反序列化为已经标记MyConverter的类Model时,MyConverter里面CanRead属性是false,反序列时是走默认反序列化,不走ReadJson()方法,json里ID属性是bool类型的,而Model里的ID属性是int类型。有三个方法可以解决:1、该模型只做序列化操作不做反序列化操作;2、新定义一个类,它的属性ID是bool类型;3、MyConverter中CanRead属性设为true,并实现ReadJson()方法。以下是第三种方法ReadJson()函数的实现:
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var model = new Model(); //获取JObject对象,该对象对应着我们要反序列化的json var jobj = serializer.Deserialize<JObject>(reader); //从JObject对象中获取键位ID的值 var id = jobj.Value<bool>("ID"); //根据id值判断,进行赋值操作 if (id) { model.ID = 1; } else { model.ID = 0; } //最终返回的model对象就是json反序列化所得到的Model对象 //主要,这里的model对象不一定非得是Model类型,ReadJson()方法与WriteJson()方法是一样的,可以自由操作反序列生成的对象或者序列化生成的json return model; }
下面附上全部代码:
class Program { static void Main(string[] args) { var model = new Model(); model.ID = 1; var json = JsonConvert.SerializeObject(model);//由于ID值为1,得到json为{"ID":ture} var newModel = JsonConvert.DeserializeObject<Model>(json);//序列化得到的newModel对象ID值为1 } [JsonConverter(typeof(MyConverter))] public class Model { public int ID { get; set; } } public class MyConverter : JsonConverter { //是否开启自定义反序列化,值为true时,反序列化时会走ReadJson方法,值为false时,不走ReadJson方法,而是默认的反序列化 public override bool CanRead => true; //是否开启自定义序列化,值为true时,序列化时会走WriteJson方法,值为false时,不走WriteJson方法,而是默认的序列化 public override bool CanWrite => true; public override bool CanConvert(Type objectType) { return typeof(Model) == objectType; } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var model = new Model(); //获取JObject对象,该对象对应着我们要反序列化的json var jobj = serializer.Deserialize<JObject>(reader); //从JObject对象中获取键位ID的值 var id = jobj.Value<bool>("ID"); //根据id值判断,进行赋值操作 if (id) { model.ID = 1; } else { model.ID = 0; } //最终返回的model对象就是json反序列化所得到的Model对象 //主要,这里的model对象不一定非得是Model类型,ReadJson方法与WriteJson方法是一样的,可以自由操作反序列生成的对象或者序列化生成的json return model; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { //new一个JObject对象,JObject可以像操作对象来操作json var jobj = new JObject(); //value参数实际上是你要序列化的Model对象,所以此处直接强转 var model = value as Model; if (model.ID != 1) { //如果ID值为1,添加一个键位"ID",值为false jobj.Add("ID",false); } else { jobj.Add("ID", true); } //通过ToString()方法把JObject对象转换成json var jsonstr = jobj.ToString(); //调用该方法,把json放进去,最终序列化Model对象的json就是jsonstr,由此,我们就能自定义的序列化对象了 writer.WriteValue(jsonstr); } } }