zoukankan      html  css  js  c++  java
  • 使用Json.Net处理json序列化和反序列化接口或继承类

    以前一直没有怎么关注过Newtonsoft的Json.Net这个第三方的.NET Json框架,主要是我以前在开发项目的时候大多数使用的都是.NET自带的Json序列化类JavaScriptSerializer,但是最近在项目中需要序列化和反序列化一个实现接口的类,而如果使用JavaScriptSerializer的话就会出现问题,我们来看看如下场景。

    首先我们有一个接口IPeople和一个实现了该接口的类Man

    interface IPeople
    {
        string Name { get; set; }
        int Age { get; set; }
    }
    
    class Man : IPeople
    {
        public string Name { get; set; }
    
        public int Age { get; set; }
    }


    我们使用JavaScriptSerializer直接序列化IPeople接口

    IPeople poeple = new Man();
    poeple.Age = 25;
    poeple.Name = "Scott";
    
    JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
    string textJson = jsSerializer.Serialize(poeple);
    poeple = jsSerializer.Deserialize<IPeople>(textJson);

    会得到序列化后的json文本textJson如下

    {"Name":"Scott","Age":25}

    我们可以看到在序列化后的json中没有任何属性说明这段json到底是由什么类序列化而来的,紧接着在JavaScriptSerializer执行jsSerializer.Deserialize<IPeople>(textJson)做反序列化的时候就抛出了异常提示IPeople没有默认无参构造函数,也就是说JavaScriptSerializer不知道应该把textJson中的json反序列化为类Man。

    而如果我们使用的是Json.NET的话,就可以完美的实现接口IPeople的序列化和反序列化,我们来看看怎么使用Json.NET的序列化和反序列化

    IPeople poeple = new Man();
    poeple.Age = 25;
    poeple.Name = "Scott";
    
    JsonSerializerSettings jsonSerializerSettings = new JsonSerializerSettings();
    jsonSerializerSettings.TypeNameHandling = TypeNameHandling.All;//这一行就是设置Json.NET能够序列化接口或继承类的关键,将TypeNameHandling设置为All后,Json.NET会在序列化后的json文本中附加一个属性说明json到底是从什么类序列化过来的,也可以设置TypeNameHandling为Auto,表示让Json.NET自动判断是否需要在序列化后的json中添加类型属性,如果序列化的对象类型和声明类型不一样的话Json.NET就会在json中添加类型属性,反之就不添加,但是我发现TypeNameHandling.Auto有时候不太好用。。。
    string textJson = JsonConvert.SerializeObject(poeple, jsonSerializerSettings);//将JsonSerializerSettings作为参数传入序列化函数,这样序列化后的Json就附带类型属性
    poeple = JsonConvert.DeserializeObject<IPeople>(textJson, jsonSerializerSettings);//将JsonSerializerSettings作为参数传入反序列化函数,这样Json.NET就会读取json文本中的类型属性,知道应该反序列化成什么类型

    这里IPeople接口能被成功序列化和返序列化的关键就是jsonSerializerSettings.TypeNameHandling = TypeNameHandling.All这行代码,我们来看看Json.NET序列化后的json文本信息

    {"$type":"Json.Man, Json","Name":"Scott","Age":25}

    可以看到Json.NET在序列化后的json文本中添加了一个属性叫$type来说明json是从Json.Man类序列化而来的,那么后面再反序列化的时候Json.NET就成功地将上面的json文本反序列化成了类Man.

    所以Json.NET在做json的序列化和反序列化的时候比JavaScriptSerializer更全面,当然在使用JavaScriptSerializer的时候自定义Converter也可以做到序列化接口和继承类,但是这要麻烦很多。这一点也会让我以后更多使用Json.NET来实现json的序列化和反序列化。

    给出一个设置TypeNameHandling.Auto的例子说明,是老外写的,我觉得将TypeNameHandling.Auto解释得很清楚了。

    Json.Net has a setting that intelligently adds type information - declare it like this:

    new JsonSerializer { TypeNameHandling = TypeNameHandling.Auto };

    This will determine whether type embedding is required and add it where necessary. Lets say I had the following classes:

    public class Message
    {
        public object Body { get; set; }
    }
    
    public class Person
    {
        public string Name { get; set; }
    }
    
    public class Manager : Person
    {
    
    }
    
    public class Department
    {
        private List<Person> _employees = new List<Person>();
        public List<Person> Employees { get { return _employees; } }
    }

    Notice the Message Body is of type object, and that Manager subclasses Person. If I serialize a Message with a Department Body that has a single Manager I get this:

    {
        "Body":
        {
            "$type":"Department, MyAssembly",
            "Employees":[
                {
                    "$type":"Manager, MyAssembly",
                    "Name":"Tim"
                }]
        }
    }


    Notice how it's added the $type property to describe the Department and Manager types. If I now add a Person to the Employees list and change the Message Body to be of type Department like this:

    public class Message
    {
        public Department Body { get; set; }
    }

    then the Body type annotation is no longer needed and the new Person is not annotated - absence of annotation assumes the element instance is of the declared array type. The serialized format becomes:

    {
        "Body":
        {
            "Employees":[
                {
                    "$type":"Manager, MyAssembly",
                    "Name":"Tim"
                },
                {
                    "Name":"James"
                }]
        }
    }

    This is an efficient approach - type annotation is only added where required. While this is .NET specific, the approach is simple enough to handle that deserializers/message types on other platforms should be fairly easily extended to handle this.

    I'd be reticent about using this in a public API though, as it is non-standard. In that case you'd want to avoid polymorphism, and make versioning and type information very explicit properties in the message.

    最后通过我写的一个例子来演示怎么自定义和使用Json.Net的转换器,这个例子还阐述了Json.Net在序列化和反序列化实现了接口IEnumerable的类时所遇到的问题,有兴趣的朋友可以下载。

    JsonNetArraySerialization.rar

  • 相关阅读:
    Angular Universal 学习笔记
    SAP Spartacus 如何获得当前渲染页面的 CMS 元数据
    Angular 服务器端渲染的学习笔记(二)
    Angular 服务器端渲染的学习笔记(一)
    第三方外部 Saas提供商如何跟使用 SAP 系统的客户进行对接接口集成
    如何从 SAP Spartacus Product Detail 页面,找到其 Angular 实现 Component 的位置
    具备自动刷新功能的 SAP ABAP ALV 报表
    C++学习目录
    c--条件编译
    c--文件读写--二进制
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/4524786.html
Copyright © 2011-2022 走看看