C#使用Newtonsoft.Json的JsonConverter解决反序列化类中的接口属性出现的问题

前言


我们在使用Newtonsoft.Json进行反序列化类中的接口属性的时候,Newtonsoft.Json会因找不到具体实现类,无法进行反序列化。

问题


Student类

public class Student
{
    public string Name { get; set; }
    //这个是用来测试泛型是否能序列化和反序列化
    public  T age { get; set; }
    
    public IClient Client { get; set; }
}

IClient和Client类

public interface IClient
{
    string Name { get; set; }
    
    void GetClient();
}

public class Client : IClient
{
    public string Name { get; set; }
    
    public void GetClient()
    {
       throw new NotImplementedException();
    }
}

program类

class Program
{
    static void Main(string[] args)
    {
        //按照正常流程来进行序列化和反序列话
        Student student = new Student()
        {
            Name = "123465",
            age = 12,
           Client = new Client()
           {
              Name = "哈哈"
           }
        };
      //序列化成Json字符串
      string json = JsonConvert.SerializeObject(student);
      
      //将Json字符串反序列化成Student对象
     Student result = JsonConvert.DeserializeObject>(json);
    
     Console.WriteLine(result.Client.Name);
    }
}

然后运行的时候反序列化那一行的时候会报错
C#使用Newtonsoft.Json的JsonConverter解决反序列化类中的接口属性出现的问题_第1张图片

Could not create an instance of type Redis测试.IClient. Type is an interface or abstract class and cannot be instantiated. Path ‘Client.Name’
百度翻译:无法创建redis测试.iclient类型的实例。类型是接口或抽象类,无法实例化。路径“client.name“

原因


我们在序列化完之后的Json是这样子的

{"Name":"123465","age":12,"Client":{"Name":"哈哈"}}

个人认为,在反序列化的时候,遇到IClient属性的时候,因为我们没有告诉序列化器该怎么序列化,然后序列化器只好按照自己反序列化对象流程走,但是它发现类型是一个接口,不能进行实例化,而它也不知道具体实现类是谁,所以就报出这个错误。

解决方式


我是用的方式是告诉序列化器,遇到这个接口时该怎么反序列化,怎么告诉呢?这得用到JsonConverter这个抽象转换类

第一种方式

定义一个ClientJsonConverter类,继承JsonConverter

class ClientJsonConverter : JsonConverter
{
     public override bool CanConvert(Type objectType)
     {
            //我们能转换任何东西
            return true;
     }
     
     public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
     {
            //显性指定要转换的实现类
            return serializer.Deserialize(reader);
     }
     
      public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
      {
              //默认序列化流程
               serializer.Serialize(writer, value);
      }
     
}

然后在我们的Student类进行添加特性

       [JsonConverter(typeof(ClientJsonConverter))]
        public IClient Client { get; set; }

然后再运行我们的控制台就正常了
在这里插入图片描述

第二种方式

第二种方式也是自定义类继承JsonConverter来解决,不过,和第一种方式不同的是,它不用我们在student类里面添加特性。

自定义ClientJsonConverter2继承JsonConverter

class ClientJsonConverter2:JsonConverter
{
     public override bool CanConvert(Type objectType)
     {
        //如果遇到了IClient,我们才进行转换
         if (objectType.FullName == typeof(IClient).FullName)
         {
              return true;
         }
         return false;
     }
    
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
            //再判断一次,如果是IClient接口,那么我们指定具体实现类型
            if (objectType.FullName == typeof(IClient).FullName)
            {
               return serializer.Deserialize(reader);
           }
    }
    
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
            //按正常流程序列化
            serializer.Serialize(writer, value);
    }
}

Student类和最上面的一样

program类

class Program
{
     static void Main(string[] args)
     {
           Student student = new Student()
           {
                Name = "123465",
                age = 12,
                Client = new Client()
                {
                    Name = "哈哈"
                }
           };
          
           //序列化成Json
           string json = JsonConvert.SerializeObject(student);
           
           //使用另一个序列化器来进行反序列化
          JsonSerializer serializer = new JsonSerializer();
          //把我们自定义的JsonConverter放进序列化器(相当于告诉序列化器该怎么序列化)
          serializer.Converters.Add(new ClientJsonConverter2());
           
           //进行反序列化
            JsonTextReader reader = new JsonTextReader(new StringReader(json));
            Student result = serializer.Deserialize>(reader);
            //输出结果
            Console.WriteLine(result.Client.Name);
     }
}

在这里插入图片描述

成功!

补充

这两种解决方法适用的环境是什么呢?第一种解决方式适用于序列化自定义的类,而类中有接口属性,第二种解决方式适用于序列化无法进行修改的类(系统类,框架定义的类等等),这些类中也有接口属性

参考

https://stackoverflow.com/questions/2254872/using-json-net-converters-to-deserialize-properties

你可能感兴趣的:(问题总结)