Fork me on GitHub
一种简单,轻量,灵活的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组件的性能测试》中的是一样的,

 测试机配置

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

 

  功能扩展

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

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

先来看一个栗子

将DataSet转为Json对象

随便来个简单个DataSet

 C#代码

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

 各组件转换结果

 

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

  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

 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中可运行代码为准

我写的文章,除了纯代码,其他的都是想表达一种思想,一种解决方案.希望各位看官不要局限于文章中的现成的代码,要多关注整个文章的主题思路,谢谢
 
分类: C#
posted on 2013-08-25 00:02  HackerVirus  阅读(258)  评论(0)    收藏  举报