• Newtonsoft.Json 的基本用法


    Ø  前言

    说起 C# JSON 的操作(序列化与反序列化),大家都会想到 JavaScriptSerializerDataContractJsonSerializer Newtonsoft.Json 等。三者都是用于操作 JSON 的框架利器,它们又有什么区别呢?本文包括:

    1.   常用 JSON 操作框架(JavaScriptSerializerDataContractJsonSerializerNewtonsoft.Json)的区别与比较

    2.   简单序列化与反序列化

    3.   匿名对象

    4.   DataTable

    5.   私有成员

    6.   指定成员名称

    7.   指定序列化成员

    8.   枚举类型成员

     

    1.   常用 JSON 操作框架(JavaScriptSerializerDataContractJsonSerializerNewtonsoft.Json)的区别与比较

    1)   区别如下:

    1.   JavaScriptSerializer,位于 System.Web.Extensions.dll 程序集,它是 .NET 自带的程序集,适用于 Web 项目中,因为每当新建一个 Web 项目后,VS 都会自动帮我引用该程序集,

     

    2.   DataContractJsonSerializer,位于 System.Runtime.Serialization.dll 程序集,也是属于 .NET 自带的程序集。适用于 WCF 项目中,因为每当新建一个 WCF 项目后,VS 都会自动帮我引用该程序集。另外,由名称可见它是一种数据契约 JSON 序列化

     

    3.   Newtonsoft.Json,一个第三方的开源类库,主要处理数据的 JSON 序列化操作,在性能或功能方面与前两者相比都有优势,官网:https://www.newtonsoft.com/json,适用于对 JSON 数据操作平凡的各种项目中。

     

    2)   性能比较

    1.   下图是 Newtonsoft.Json 官网给出的执行耗时比较

    clip_image002[1]

     

    2.   Newtonsoft.Json 官网当然说自己的牛逼,所以,本人在本机进行了代码验证,代码如下:

    string jssStr, dcjsStr, jcStr;

    Person[] jssArr, dcjsArr, jcArr;

    int count = 100000;

    Person[] persons = new Person[count];

    for (int i = 0; i < count; i++)

    {

        persons[i] = new Person()

        {

            Name = string.Format("李三毛_{0}", i),

            Age = 29,

            Sex = true,

            Address = "湖北省利川市",

            Spouse = new Person()

            {

                Name = string.Format("大美妞_{0}", i),

                Age = 25,

                Sex = false,

                Address = "湖北省利川市",

                Spouse = null

            }

        };

    }

    System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();

    //3.1 JavaScriptSerializer

    JavaScriptSerializer jss = new JavaScriptSerializer();

    jss.MaxJsonLength = 92097152;    //默认为:2097152

     

    stopwatch.Restart();

    jssStr = jss.Serialize(persons);

    stopwatch.Stop();

    Console.WriteLine("JavaScriptSerializer Serialize Time{0:F1}s,{1}ms】,String Length:{2}",

        TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds).TotalSeconds, stopwatch.ElapsedMilliseconds, jssStr.Length);

     

    stopwatch.Restart();

    jssArr = jss.Deserialize<Person[]>(jssStr);

    stopwatch.Stop();

    Console.WriteLine("JavaScriptSerializer Deserialize Time{0:F1}s,{1}ms】,Array Length:{2}",

        TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds).TotalSeconds, stopwatch.ElapsedMilliseconds, jssArr.Length);

     

    //3.2 DataContractJsonSerializer

    DataContractJsonSerializer dcjs = new DataContractJsonSerializer(typeof(Person[]));

    stopwatch.Restart();

    using (MemoryStream stream = new MemoryStream())

    {

        dcjs.WriteObject(stream, persons);

        dcjsStr = Encoding.UTF8.GetString(stream.ToArray());

    }

    stopwatch.Stop();

    Console.WriteLine("DataContractJsonSerializer Serialize Time{0:F1}s,{1}ms】,String Length:{2}",

        TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds).TotalSeconds, stopwatch.ElapsedMilliseconds, dcjsStr.Length);

     

    stopwatch.Restart();

    using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(dcjsStr)))

    {

        dcjsArr = dcjs.ReadObject(stream) as Person[];

    }

    stopwatch.Stop();

    Console.WriteLine("DataContractJsonSerializer Deserialize Time{0:F1}s,{1}ms】,Array Length:{2}",

        TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds).TotalSeconds, stopwatch.ElapsedMilliseconds, dcjsArr.Length);

     

    //3.3 Newtonsoft.Json

    stopwatch.Restart();

    jcStr = JsonConvert.SerializeObject(persons);

    stopwatch.Stop();

    Console.WriteLine("Newtonsoft.Json Serialize Time{0:F1}s,{1}ms】,String Length:{2}",

        TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds).TotalSeconds, stopwatch.ElapsedMilliseconds, jcStr.Length);

     

    stopwatch.Restart();

    jcArr = JsonConvert.DeserializeObject<Person[]>(jcStr);

    stopwatch.Stop();

    Console.WriteLine("Newtonsoft.Json Deserialize Time{0:F1}s,{1}ms】,Array Length:{2}",

        TimeSpan.FromMilliseconds(stopwatch.ElapsedMilliseconds).TotalSeconds, stopwatch.ElapsedMilliseconds, jcArr.Length);

     

    Ø  运行结果(三者分别运行三次后的最短耗时)

    1.   Serialize(序列化)

    1)   DataContractJsonSerializer Serialize Time0.7s,696ms】,String Length:14377781

    2)   Newtonsoft.Json Serialize Time1.7s,1741ms】,String Length:14377781

    3)   JavaScriptSerializer Serialize Time6.2s,6189ms】,String Length:14377781

    2.   Deserialize(反序列化)

    1)   DataContractJsonSerializer Deserialize Time2.0s,2037ms】,Array Length:100000

    2)   Newtonsoft.Json Deserialize Time2.4s,2407ms】,Array Length:100000

    3)   JavaScriptSerializer Deserialize Time3.7s,3733ms】,Array Length:100000

     

    Ø  可见,耗时最短的并不是 Newtonsoft.Json,而是 .NET 自带的 DataContractJsonSerializer,最差的是 JavaScriptSerializer,序列化用了6秒,而 DataContractJsonSerializer 则之需要1秒时间不到。所以这一局,DataContractJsonSerializer 胜出,而 Newtonsoft.Json 则稍微靠后,由于它的功能方面比较强大,所以还是继续研究它。

     

    Ø  首先,我们定义一个测试的类,并创建类的实例和一个匿名对象(后面的示例基本都使用该类)

    1.   定义测试类(Goods 为一个部分类)

    /// <summary>

    /// 商品

    /// </summary>

    public partial class Goods

    {

        /// <summary>

        /// 商品Id

        /// </summary>

        public int GoodsId { get; set; }

     

        /// <summary>

        /// 商品名称

        /// </summary>

        public string GoodsName { get; set; }

     

        /// <summary>

        /// 价格

        /// </summary>

        public decimal Price { get; set; }

     

        /// <summary>

        /// 是否限购

        /// </summary>

        public bool IsQuota { get; set; }

     

        /// <summary>

        /// 商品属性数组

        /// </summary>

        public Attribute[] Attributes { get; set; }

     

        /// <summary>

        /// 商品属性

        /// </summary>

        public class Attribute

        {

            public string Name { get; set; }

            public string Value { get; set; }

        }

    }

     

    2.   创建类的实例

    Goods[] goods = new Goods[]

    {

        new Goods()

        {

            GoodsId = 1,

            GoodsName = "联想ThinkPad无线鼠标",

            Price = 125.00m,

            IsQuota = true,

            Attributes = new Goods.Attribute[]

            {

                new Goods.Attribute() { Name = "品牌", Value = "Lenovo/联想" },

                new Goods.Attribute() { Name = "颜色", Value = "黑色" }

            }

        }

    };

    var anonymousGoods = new[]

    {

        new

        {

            GoodsId = 2,

            GoodsName = "联想ThinkPad无线键盘",

            Price = 286.00m,

            IsQuota = false,

            Attributes = new []

            {

                new { Name = "品牌", Value = "Lenovo/联想" },

                new { Name = "颜色", Value = "白色" }

            }

        }

    };

     

    2.   简单序列化与反序列化

    1)   序列化

    序列化通常使用 JsonConvert 类的 SerializeObject 方法,该方法有 6 个重载方法,例如:

    string jsonStr1_1 = JsonConvert.SerializeObject(goods);

    结果:

    [{"GoodsId":1,"GoodsName":"联想ThinkPad无线鼠标","Price":125.00,"IsQuota":true,"Attributes":[{"Name":"品牌","Value":"Lenovo/联想"},{"Name":"颜色","Value":"黑色"}]}]

     

    2)   反序列化

    序列化通常使用 JsonConvert 类的 DeserializeObject 方法,该方法有 8 个重载方法,例如:

    Goods[] jsonObj1_1 = JsonConvert.DeserializeObject<Goods[]>(jsonStr1_1);

    结果:

    clip_image003[1]

     

    3.   匿名对象

    1)   序列化

    string jsonStr1_2 = JsonConvert.SerializeObject(anonymousGoods);

    结果:

    [{"GoodsId":2,"GoodsName":"联想ThinkPad无线键盘","Price":286.00,"IsQuota":false,"Attributes":[{"Name":"品牌","Value":"Lenovo/联想"},{"Name":"颜色","Value":"白色"}]}]

     

    2)   反序列化

    var jsonObj1_2 = JsonConvert.DeserializeAnonymousType(jsonStr1_2, anonymousGoods);

    结果:

    clip_image004[1]

     

    4.   DataTable

    首先,创建一个 DataTable 对象并插入数据

    DataTable dataTable = new DataTable();

    dataTable.Columns.AddRange(new DataColumn[]

    {

        new DataColumn() { ColumnName = "GoodsId", DataType = typeof(int) },

        new DataColumn() { ColumnName = "GoodsName", DataType = typeof(string) },

        new DataColumn() { ColumnName = "Price", DataType = typeof(decimal) }

    });

    for (int i = 0; i < 2; i++)

    {

        DataRow dataRow = dataTable.NewRow();

        dataRow["GoodsId"] = i + 1;

        dataRow["GoodsName"] = string.Format("测试商品{0}", i + 1);

        dataRow["Price"] = i + 101;

        dataTable.Rows.Add(dataRow);

    }

     

    1)   序列化

    string jsonStr3_1 = JsonConvert.SerializeObject(dataTable);

    结果:[{"GoodsId":1,"GoodsName":"测试商品1","Price":101.0},{"GoodsId":2,"GoodsName":"测试商品2","Price":102.0}]

     

    2)   反序列化

    DataTable jsonObj3_1 = JsonConvert.DeserializeObject<DataTable>(jsonStr3_1);

    结果:

    clip_image005[1]

     

    5.   私有成员(以 PriceIsQuota 为例

    Newtonsoft.Json 默认是不处理 private(私有)成员的,如非要处理也是可以的,在私有成员上标记 JsonPropertyAttribute 特性即可,例如(修改 Goods):

    private decimal _price = 126;

    /// <summary>

    /// 价格

    /// </summary>

    private decimal Price { get { return _price; } set { _price = value; } }

     

    private bool _isQuota = true;

    /// <summary>

    /// 是否限购

    /// </summary>

    [JsonProperty]

    private bool IsQuota { get { return _isQuota; } set { _isQuota = value; } }

     

    1)   序列化

    string jsonStr4_1 = JsonConvert.SerializeObject(goods);

    结果:

    [{"GoodsId":1,"GoodsName":"联想ThinkPad无线鼠标","IsQuota":true,"Attributes":[{"Name":"品牌","Value":"Lenovo/联想"},{"Name":"颜色","Value":"黑色"}]}]

     

    2)   反序列化

    Goods[] jsonObj4_1 = JsonConvert.DeserializeObject<Goods[]>(jsonStr4_1);

    结果:

    clip_image006

     

    6.   指定成员名称

    使用 JsonPropertyAttribute 特性的 PropertyName 属性指定 JSON 成员名称,例如(修改 Goods

    [JsonProperty("att_name")]

    public string Name { get; set; }

    [JsonProperty("att_val")]

    public string Value { get; set; }

     

    1)   序列化

    string jsonStr5_1 = JsonConvert.SerializeObject(goods);

    结果:

    [{"GoodsId":1,"GoodsName":"联想ThinkPad无线鼠标","IsQuota":true,"Attributes":[{"att_name":"品牌","att_val":"Lenovo/联想"},{"att_name":"颜色","att_val":"黑色"}]}]

     

    2)   反序列化

    Goods[] jsonObj5_1 = JsonConvert.DeserializeObject<Goods[]>(jsonStr5_1);

    结果:

    clip_image007

     

    7.   指定序列化成员

    Newtonsoft.Json 提供三种序列化模式,使用 Newtonsoft.Json.MemberSerialization 枚举表示。例如(修改 Goods):

    [JsonObject(Newtonsoft.Json.MemberSerialization.OptIn)]

    public class Goods {...}

    /// <summary>

    /// 商品名称

    /// </summary>

    [JsonProperty]

    public string GoodsName { get; set; }

    OptOut

    默认值,序列化所有共有成员,可以使用 JsonIgnore 特性,标记不需要序列化的成员。

    OptIn

    只序列化标记 JsonProperty 特性的成员。

    Fields

    只序列化字段成员。注意:默认情况下字段也支持序列化和反序列化。

     

    1)   序列化

    string jsonStr6_1 = JsonConvert.SerializeObject(goods);

    结果:[{"GoodsName":"联想ThinkPad无线鼠标","IsQuota":true}]

     

    2)   反序列化

    Goods[] jsonObj6_1 = JsonConvert.DeserializeObject<Goods[]>(jsonStr6_1);

    结果:

    clip_image008

     

    8.   枚举类型成员

    枚举类型成员默认情况下,是序列化枚举类型的值。如果希望序列化成员名称,需要在成员上标记 JsonConverter 特性,并指定 Newtonsoft.Json.Converters.StringEnumConverter 类型,例如(修改 Goods):

    /// <summary>

    /// 商品状态

    /// </summary>

    public enum Status

    {

        /// <summary>

        ///

        /// </summary>

        None = 0,

        /// <summary>

        /// 上架

        /// </summary>

        Online = 1,

        /// <summary>

        /// 下架

        /// </summary>

        Offline = 2

    }

    /// <summary>

    /// 商品扩展

    /// </summary>

    public partial class Goods

    {

        /// <summary>

        /// 商品状态

        /// </summary>

        [JsonProperty]

        [JsonConverter(typeof(Newtonsoft.Json.Converters.StringEnumConverter))]

        public Status Status { get; set; }

    }

     

    1)   序列化

    string jsonStr7_1 = JsonConvert.SerializeObject(goods);

    结果:[{"GoodsName":"联想ThinkPad无线鼠标","IsQuota":true,"Status":"Online"}]

     

    2)   反序列化

    Goods[] jsonObj7_1 = JsonConvert.DeserializeObject<Goods[]>(jsonStr7_1);

    结果:

    clip_image009

  • 相关阅读:
    Lucence.Net 2.9.3 日期范围搜索
    Frida 使用
    ubuntu+php5fpm 下安装 memcached PHP扩展
    cmd下使用telnet连接到memcached服务器操作
    解决sendmail卡死和主机名为bogon的问题
    【转载】Win7文件关联 文件与程序“联姻”
    [转载]Ubuntu下Samba服务器的最简配置
    Windows XP快速关机
    [转载]Git安装以及使用Git 管理个人文档
    GitHub push时提示“fatal: The remote end hung up unexpectedly”
  • 原文地址:https://www.cnblogs.com/abeam/p/8295765.html
Copyright © 2020-2023  润新知