zoukankan      html  css  js  c++  java
  • 一种简单,轻量,灵活的C#对象转Json对象的方案(续)

    本文参考资料

    一种简单,轻量,灵活的C#对象转Json对象的方案

    [源码]Literacy 快速反射读写对象属性,字段

      一段废话

    之前我已经介绍了这个方案的名称为JsonBuilder,这套方案最大的好处在于它的灵活可扩展性上,所以我可以很方便的对他进行优化和扩展!

      性能优化

    JsonBuilder第一版对一般对象的是进行实时反射的,所以性能不会很好,所以我首先想到的是优化他的性能

    看我前几天发表过一篇《[源码]Literacy 快速反射读写对象属性,字段》的文章,这东西的效率不错,用来代替反射正好。

    我把优化后的类取名QuickJsonBuilder

    在继承JsonBuilder的基础上,我仅仅需要重写一个方法

    public class QuickJsonBuilder : JsonBuilder
    {
        protected override void AppendOther(object obj)
        {
            Literacy lit = new Literacy(obj.GetType());
            string fix = "";
            Buff.Append('{');
            foreach (var p in lit.Property)
            {
                Buff.Append(fix);
                AppendKey(p.Name, false);
                AppendObject(p.GetValue(obj));
    fix = ','; } Buff.Append(
    '}'); } }

    像这样我很简单的将原来的实时反射改成了Literacy

    但是这样显然并不能保证性能,所以我还要加一个缓存

    static Dictionary<Type, Literacy> _LitCache = new Dictionary<Type, Literacy>();
    
    protected override void AppendOther(object obj)
    {
        Literacy lit;
        Type type = obj.GetType();
    
        if (_LitCache.TryGetValue(type, out lit) == false)
        {
            lock (_LitCache)
            {
                if (_LitCache.TryGetValue(type, out lit) == false)
                {
                    lit = new Literacy(type);
                    _LitCache.Add(type, lit);
                }
            }
        }
    
        string fix = "";
        Buff.Append('{');
        foreach (var p in lit.Property)
        {
            Buff.Append(fix);
            AppendKey(p.Name, false);
            AppendObject(p.GetValue(obj));
    fix = ','; } Buff.Append(
    '}'); }

     缓存本身是全局静态的,所以为了防止多线程并发的问题,特别加了锁

    再为了它能性能能够好上那么一点点(更多的是为了自己的强迫症吧....),再修改一些地方

    static Dictionary<Type, Literacy> _LitCache = new Dictionary<Type, Literacy>();
    
    protected override void AppendOther(object obj)
    {
        Literacy lit;
        Type type = obj.GetType();
    
        if (_LitCache.TryGetValue(type, out lit) == false)
        {
            lock (_LitCache)
            {
                if (_LitCache.TryGetValue(type, out lit) == false)
                {
                    lit = new Literacy(type);
                    _LitCache.Add(type, lit);
                }
            }
        }
    
    
        Buff.Append('{');
        var ee = lit.Property.GetEnumerator();
    
        if (ee.MoveNext())
        {
            AppendKey(ee.Current.Name, false);
            AppendObject(ee.Current.GetValue(obj));
            while (ee.MoveNext())
            {
                Buff.Append(',');
                AppendKey(ee.Current.Name, false);
                AppendObject(ee.Current.GetValue(obj));
            }
        }
    
        Buff.Append('}');
    }

     好了来看看他和他父亲在性能上的差异:

    测试代码和《几个常用Json组件的性能测试》中的是一样的,

    I7-2630 4核8线程 主频2.0
    
    内存 1600 4G*2
    
    没有显卡
    
    硬盘 闪迪 msata 128 r:500m/s w:350m/s
    测试机配置

    不过今天在自己的电脑上运行了,感觉和昨天的测试结果的差异还是有些大的,所以还是那句话:测试结果因配置不同会有所出入,此结果仅供参考

      功能扩展

    相比较性能优化来说 这个要更重要一些,随着现在硬件各种不值钱,性能上的问题绝对可以在硬件上解决,而功能不足却是大多数时候我们放弃一个现成类库的原因

    在这个时候一个类库是否可扩展就显得尤为重要了。

    先来看一个栗子

    将DataSet转为Json对象

    随便来个简单个DataSet

    DataTable dt1 = new DataTable("User");
    dt1.Columns.Add("UID", typeof(Guid));
    dt1.Columns.Add("Name", typeof(string));
    dt1.Columns.Add("Birthday", typeof(DateTime));
    dt1.Columns.Add("Sex", typeof(int));
    dt1.Columns.Add("IsDeleted", typeof(bool));
    dt1.Rows.Add(Guid.NewGuid(), "blqw", DateTime.Parse("1986-10-29"), 1, false);
    dt1.Rows.Add(Guid.NewGuid(), "小明", DateTime.Parse("1990-1-1"), 1, false);
    dt1.Rows.Add(Guid.NewGuid(), "小华", DateTime.Parse("1990-2-2"), 0, false);
    
    
    DataTable dt2 = new DataTable("UserInfo");
    dt2.Columns.Add("ID", typeof(int));
    dt2.Columns.Add("UID", typeof(Guid));
    dt2.Columns.Add("Address", typeof(string));
    dt2.Columns.Add("ZipCode", typeof(int));
    dt2.Rows.Add(1, dt1.Rows[0][0], "广州", 100000);
    dt2.Rows.Add(2, dt1.Rows[1][0], "上海", 200000);
    dt2.Rows.Add(3, dt1.Rows[2][0], "背景", 300000);
    
    
    DataSet ds = new DataSet();
    ds.Tables.Add(dt1);
    ds.Tables.Add(dt2);
    C#代码

    再来看看每个组件的转换结果

    //JsonBuilder 
    
    var a = {"User":{"columns":["UID","Name","Birthday","Sex","IsDeleted"],"rows":[["58cc6573-cb34-4d82-9343-166a3d23f518","blqw","1986-10-29 00:00:00",1,false],["c1ce
    27aa-383c-4a90-b180-4f8827ef64a9","小明","1990-01-01 00:00:00",1,false],["79d24a02-7d90-4ade-80c5-93b57314f55b","小华","1990-02-02 00:00:00",0,false]]},"UserInf
    o":{"columns":["ID","UID","Address","ZipCode"],"rows":[[1,"58cc6573-cb34-4d82-9343-166a3d23f518","广州",100000],[2,"c1ce27aa-383c-4a90-b180-4f8827ef64a9","上海"
    ,200000],[3,"79d24a02-7d90-4ade-80c5-93b57314f55b","背景",300000]]}}
    //==============================================
    
    //QuickJsonBuilder 
    
    var a = {"User":{"columns":["UID","Name","Birthday","Sex","IsDeleted"],"rows":[["58cc6573-cb34-4d82-9343-166a3d23f518","blqw","1986-10-29 00:00:00",1,false],["c1ce
    27aa-383c-4a90-b180-4f8827ef64a9","小明","1990-01-01 00:00:00",1,false],["79d24a02-7d90-4ade-80c5-93b57314f55b","小华","1990-02-02 00:00:00",0,false]]},"UserInf
    o":{"columns":["ID","UID","Address","ZipCode"],"rows":[[1,"58cc6573-cb34-4d82-9343-166a3d23f518","广州",100000],[2,"c1ce27aa-383c-4a90-b180-4f8827ef64a9","上海"
    ,200000],[3,"79d24a02-7d90-4ade-80c5-93b57314f55b","背景",300000]]}}
    //==============================================
    
    //fastJSON.NET 
    
    var a = {"User":[["f1a4f526-e723-4fb4-930e-0b5250ee3309","blqw","1986-10-29 00:00:00",1,false],["32b289a2-f116-47c3-99cc-0a7804706490","小明","1990-01-01 00:00:00"
    ,1,false],["a2ca668f-151e-4863-8979-d5a5e7c83a35","小华","1990-02-02 00:00:00",0,false]],"UserInfo":[[1,"f1a4f526-e723-4fb4-930e-0b5250ee3309","广州",100000],[2
    ,"32b289a2-f116-47c3-99cc-0a7804706490","上海",200000],[3,"a2ca668f-151e-4863-8979-d5a5e7c83a35","背景",300000]]}
    ==============================================
    
    //Jayrock.Json 
    
    var a = {"User":[{"UID":"58cc6573-cb34-4d82-9343-166a3d23f518","Name":"blqw","Birthday":"1986-10-29T00:00:00.0000000+08:00","Sex":1,"IsDeleted":false},{"UID":"c1ce
    27aa-383c-4a90-b180-4f8827ef64a9","Name":"小明","Birthday":"1990-01-01T00:00:00.0000000+08:00","Sex":1,"IsDeleted":false},{"UID":"79d24a02-7d90-4ade-80c5-93b573
    14f55b","Name":"小华","Birthday":"1990-02-02T00:00:00.0000000+08:00","Sex":0,"IsDeleted":false}],"UserInfo":[{"ID":1,"UID":"58cc6573-cb34-4d82-9343-166a3d23f518
    ","Address":"广州","ZipCode":100000},{"ID":2,"UID":"c1ce27aa-383c-4a90-b180-4f8827ef64a9","Address":"上海","ZipCode":200000},{"ID":3,"UID":"79d24a02-7d90-4ade-8
    0c5-93b57314f55b","Address":"背景","ZipCode":300000}]}
    //==============================================
    
    //Newtonsoft.Json 
    
    var a = {"User":[{"UID":"58cc6573-cb34-4d82-9343-166a3d23f518","Name":"blqw","Birthday":"/Date(530899200000+0800)/","Sex":1,"IsDeleted":false},{"UID":"c1ce27aa-3
    83c-4a90-b180-4f8827ef64a9","Name":"小明","Birthday":"/Date(631123200000+0800)/","Sex":1,"IsDeleted":false},{"UID":"79d24a02-7d90-4ade-80c5-93b57314f55b","Nam
    e":"小华","Birthday":"/Date(633888000000+0800)/","Sex":0,"IsDeleted":false}],"UserInfo":[{"ID":1,"UID":"58cc6573-cb34-4d82-9343-166a3d23f518","Address":"广州"
    ,"ZipCode":100000},{"ID":2,"UID":"c1ce27aa-383c-4a90-b180-4f8827ef64a9","Address":"上海","ZipCode":200000},{"ID":3,"UID":"79d24a02-7d90-4ade-80c5-93b57314f55b",
    "Address":"背景","ZipCode":300000}]}
    //==============================================
    
    //ServiceStack.Text 报错
    //TestJavaScriptSerializer 报错
    各组件转换结果

    我们可以很清楚的发现每个组件都有各自的转换方式,结果都不相同

    1. fastJSON.NET  结果中每列的"列名"丢失了
    2. Jayrock.Json 算是比较标准的格式了
    3. Newtonsoft.Json 数据格式和Jayrock.Json类似,但是时间格式太蛋疼了,造成的结果就是这个字符串直接在网页js中运行是不可能的,需要2次转换
    4. TestJavaScriptSerializer 报错,无法转换
    5. TestServiceStack 报错,无法转换
    6. JsonBuilder,因为是我自己写的,所以有自己的格式,我习惯将Table转换为2个部分一个columns,一个rows,因为在行数多的情况下,列名每次都重复会增加数据大小

    以上几个组件的结果 可能可以通过参数设置,我不确定 但即使是参数设定,也只不过是选择几种预置的格式罢了。

    这时候JsonBuilder灵活性就显现出来了

    假设我现在的项目有以下需求:

    1. DataTable转换需要可以在,Jayrock.Json和JsonBuilder格式之间切换
    2. DateTime可以在 Data,Time,DataTime 3种模式中切换
    3. Guid要去掉中间的连字符(-)
    4. true,false要转换为1,0

    OK 现在我需要重写4个方法 AppendDataTable(如果有必要也一起重写AppendDataView),AppendDateTime,AppendGuid,AppendBoolean

    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Text;
    
    namespace blqw
    {
        class MyJsonBuilder : QuickJsonBuilder
        {
            /// <summary> 表风格
            /// <para> 默认 { columns:[colname,colname2],rows:[[x,x],[y,y]] } </para>
            /// <para> 1    [{ colname:x,colname2:x },{ colname:y,colname2:y }] </para>
            /// </summary>
            public int TableStyle { get; set; }
            /// <summary> 时间风格
            /// <para> 默认 yyyy-MM-dd HH:mm:ss </para>
            /// <para> 1    yyyy-MM-dd </para>
            /// <para> 2    HH:mm:ss </para>
            /// </summary>
            public int DateTimeStyle { get; set; }
    
            protected override void AppendDateTime(DateTime value)
            {
                switch (DateTimeStyle)
                {
                    case 1:
                        Buff.Append('"');
                        Buff.Append(value.ToString("yyyy-MM-dd"));
                        Buff.Append('"');
                        break;
                    case 2:
                        Buff.Append('"');
                        Buff.Append(value.ToString("HH:mm:ss"));
                        Buff.Append('"');
                        break;
                    default:
                        base.AppendDateTime(value);
                        break;
                }
            }
    
            protected override void AppendGuid(Guid value)
            {
                Buff.Append('"');
                Buff.Append(value.ToString("N"));
                        Buff.Append('"');
            }
    
            protected override void AppendBoolean(bool value)
            {
                base.AppendNumber(value.GetHashCode());
            }
    
            protected override void AppendDataTable(System.Data.DataTable table)
            {
                if (TableStyle == 1)
                {
                    Buff.Append('[');
                    var fix = "";
                   
                    foreach (DataRow row in table.Rows)
                    {
                        Buff.Append(fix);
                        var fix2 = "";
                        Buff.Append('{');
                        foreach (DataColumn col in table.Columns)
                        {
                            Buff.Append(fix2);
                            AppendKey(col.ColumnName,false);
                            AppendObject(row[col]);
                            fix2 = ",";
                        }
                        Buff.Append('}');
                        fix = ",";
                    }
                    Buff.Append(']');
                }
                else
                {
                    base.AppendDataTable(table);
                }
            }
    
        }
    }
    C#代码 

    然后就可以调用了

    MyJsonBuilder jb = new MyJsonBuilder();
    Console.WriteLine("TableStyle=1 ; DateTimeStyle=1");
    jb.TableStyle = 1;
    jb.DateTimeStyle = 1;
    Console.WriteLine(jb.ToJsonString(ds));
    
    Console.WriteLine("");
    Console.WriteLine("TableStyle=0 ; DateTimeStyle=2");
    jb.TableStyle = 0;
    jb.DateTimeStyle = 2;
    Console.WriteLine(jb.ToJsonString(ds));

     结果

    TableStyle=1 ; DateTimeStyle=1
    {"User":[{"UID":"0f3f70f0939546d8803d8cd0ef4de8ec","Name":"blqw","Birthday":"1986-10-29","Sex":1,"IsDeleted":0},{"UID":"72489efcbc694801a358b697414892ee","Name":"小明","Birthday":"1990-01-01","Sex":1,"IsDeleted":0},{"UID":"865cddbb1f0c427e97a724844c35a83d","Name":"小华","Birthday":"1990-02-02","Sex":0,"IsDeleted":0}],"UserInfo":[{"ID":1,"UID":"0f3f70f0939546d8803d8cd0ef4de8ec","Address":"广州","ZipCode":100000},{"ID":2,"UID":"72489efcbc694801a358b697414892ee","Address":"上海","ZipCode":200000},{"ID":3,"UID":"865cddbb1f0c427e97a724844c35a83d","Address":"背景","ZipCode":300000}]}
    
    TableStyle=0 ; DateTimeStyle=2
    {"User":{"columns":["UID","Name","Birthday","Sex","IsDeleted"],"rows":[["0f3f70f0939546d8803d8cd0ef4de8ec","blqw","00:00:00",1,0],["72489efcbc694801a358b697414892ee","小明","00:00:00",1,0],["865cddbb1f0c427e97a724844c35a83d","小华","00:00:00",0,0]]},"UserInfo":{"columns":["ID","UID","Address","ZipCode"],"rows":[[1,"0f3f70f0939546d8803d8cd0ef4de8ec","广州",100000],[2,"72489efcbc694801a358b697414892ee","上海",200000],[3,"865cddbb1f0c427e97a724844c35a83d","背景",300000]]}}
    请按任意键继续. . .

      比完整Demo还要完整的Demo下载

     点击下载

    ps 此Demo中包含了一些我下一篇文章会写的内容,如果里面的代码和文章中的不完全一样,以Demo中可运行代码为准

  • 相关阅读:
    platform_device和platform_driver
    理解和认识udev
    platform_device和platform_driver
    bzImage的概要生成过程
    shell 字符表
    分析mtk6516如何加入自己的驱动
    理解和使用Linux的硬件抽象层HAL
    bzImage的概要生成过程
    理解和认识udev
    shell 字符表
  • 原文地址:https://www.cnblogs.com/blqw/p/3277859.html
Copyright © 2011-2022 走看看