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

  • 相关阅读:
    png 的特点
    UIImangeView的用法
    uiTextView简单的用法
    UITextField简单的用法
    UIWindow的简单实用(二)
    UIView的简单实用
    objective-C 复合(组合)
    OC
    objective-C protocol协议
    object-C NSDate
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/4524786.html
Copyright © 2011-2022 走看看