一种简单,轻量,灵活的C#对象转Json对象的方案(续)
本文参考资料
一段废话
之前我已经介绍了这个方案的名称为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- 4核8线程 主频2. 内存 4G* 没有显卡 硬盘 闪迪 msata 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"), , false);
dt1.Rows.Add(Guid.NewGuid(), "小明", DateTime.Parse("1990-1-1"), , false);
dt1.Rows.Add(Guid.NewGuid(), "小华", DateTime.Parse("1990-2-2"), , 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(, dt1.Rows[][], "广州", );
dt2.Rows.Add(, dt1.Rows[][], "上海", );
dt2.Rows.Add(, dt1.Rows[][], "背景", );
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 报错
各组件转换结果
我们可以很清楚的发现每个组件都有各自的转换方式,结果都不相同
- fastJSON.NET 结果中每列的"列名"丢失了
- Jayrock.Json 算是比较标准的格式了
- Newtonsoft.Json 数据格式和Jayrock.Json类似,但是时间格式太蛋疼了,造成的结果就是这个字符串直接在网页js中运行是不可能的,需要2次转换
- TestJavaScriptSerializer 报错,无法转换
- TestServiceStack 报错,无法转换
- JsonBuilder,因为是我自己写的,所以有自己的格式,我习惯将Table转换为2个部分一个columns,一个rows,因为在行数多的情况下,列名每次都重复会增加数据大小
以上几个组件的结果 可能可以通过参数设置,我不确定 但即使是参数设定,也只不过是选择几种预置的格式罢了。
这时候JsonBuilder灵活性就显现出来了
假设我现在的项目有以下需求:
- DataTable转换需要可以在,Jayrock.Json和JsonBuilder格式之间切换
- DateTime可以在 Data,Time,DataTime 3种模式中切换
- Guid要去掉中间的连字符(-)
- 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 :
Buff.Append('"');
Buff.Append(value.ToString("yyyy-MM-dd"));
Buff.Append('"');
break;
case :
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 == )
{
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 = ;
jb.DateTimeStyle = ;
Console.WriteLine(jb.ToJsonString(ds)); Console.WriteLine("");
Console.WriteLine("TableStyle=0 ; DateTimeStyle=2");
jb.TableStyle = ;
jb.DateTimeStyle = ;
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#对象转Json对象的方案(续)的更多相关文章
- 一种简单,轻量,灵活的C#对象转Json对象的方案
简单,是因为只有一个类 轻量,是因为整个类代码只有300行 灵活,是因为扩展方式只需要继承重写某个方法即可 补充:修正无法处理可空值类型的bug 首先我将这个类称之为JsonBuilder,我希望它以 ...
- flutter最简单轻量便捷的路由管理方案NavRouter
大家好,我是CrazyQ1,今天给大家推荐一个路由管理方案,用的非常不错的,叫nav_router. 项目地址是:https://github.com/fluttercandies/nav_route ...
- Bourbon – 简单轻量的 Sass 混入(Mixins)库
Bourbon 是一个简单易用的 Sass 混入(Mixin)库,无需配置.该混入包含用于支持所有现代浏览器的 CSS3 属性前缀.前缀需要确保在旧的浏览器支持优雅降级.Bourbon 使用 SCSS ...
- quilljs 一款简单轻量的富文本编辑器(适合移动端)
quilljs入门使用教程: quill.js是一款强大的现代富文本编辑器插件.该富文本编辑器插件支持所有的现代浏览器.平板电脑和手机.它提供了文本编辑器的所有功能,并为开发者提供大量的配置参数和方法 ...
- elasticsearch(4) 轻量搜索
一 空搜索 搜索API的最基础的形式是没有指定任何查询的空搜索 ,它简单地返回集群中所有索引下的所有文档: 示例 GET 127.0.0.1:9200/_search 响应 { , "tim ...
- C# WebService的简单和复杂参数类型和结果的JSON格式
Jquery作为一款优秀的JS框架,简单易用的特性就不必说了.在实际的开发过程中,使用JQ的AJAX函数调用WebService 的接口实现AJAX的功能也成了一种比较普遍的技术手段了.WebServ ...
- Prezento – 轻量、简单的 jQuery 幻灯片插件
Prezento 是一个超级简单的 jQuery 幻灯片插件.可以让你网页以新颖的交互方式呈现.另外,Prezento 支持响应式设计,配置项也很灵活,可以根据你需要的效果配置. 您可能感兴趣的相关文 ...
- 轻量简单好用的C++JSON库CJsonObject
1. JSON概述 JSON: JavaScript 对象表示法( JavaScript Object Notation) .是一种轻量级的数据交换格式. 它基于ECMAScript的一个子集.许多编 ...
- .Net轻量状态机Stateless的简单应用
对于大部分系统中流程的变更,是十分正常的事情,小到一个状态的切换,大到整个系统都是围绕业务流再走,复杂点的有工作流引擎,简单点的几个if/else收工,但是往往有那种,心有余而力不足的,比简单复杂,比 ...
随机推荐
- 启动了VSAN服务的主机不在vCenter集群中
背景: 这个问题的来源是,某用户将该ESXi主机直接夺取到另一个vCenterA的管辖中,而这个vCenterA中集群A开启了VSAN功能,导致再次反向夺取到vCenterB中的时候带有了来自于集群A ...
- inline-block元素间距问题的几种解决方案
不知道大家有没有碰到过设置了display:inline-block;的几个相邻元素之间有几px间距的问题,这里提供几种简单实用的解决方法,希望能够帮到大家! 方法1. 将<li>标签 ...
- CRL快速开发框架系列教程六(分布式缓存解决方案)
本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...
- FFmpeg + SoundTouch实现音频的变调变速
本文使用FFmpeg + SoundTouch实现将音频解码后,进行变调变速处理,并将处理后的结果保存为WAV文件. 主要有以下内容: 实现一个FFmpeg的工具类,保存多媒体文件所需的解码信息 将解 ...
- 卸载oracle之后,如何清除注册表
之前卸载了oracle,今天偶然间发现,在服务和应用程序里面,还残存着之前的oracle服务.原来,还需要去清理下注册表. 在开始菜单的这个框里面 输入regedit,进入注册表.找到这个目录 HKE ...
- c# 基础 object ,new操作符,类型转换
参考页面: http://www.yuanjiaocheng.net/webapi/config-webapi.html http://www.yuanjiaocheng.net/webapi/web ...
- C++的内存泄漏检测【转载】
原文地址: http://www.cnblogs.com/jily/p/6239514.html
- 满堂红CIO邓劲翔:房屋中介突围
人脸识别.客户关系管理进度监控.业务流程实时监控.网站访问人数及流量实时监控等实际企业应用场景淋漓尽致.羽羽如生的以大屏幕上图表形式展现在人们面前,如果你不去继续询问,你不会知道这是一家才刚刚在房地产 ...
- 【每日一linux命令2】命令执行顺序:
二.命令顺序: 若在 shell 内置的命令/bin 以及/usr/bin 之下都出现了命令 pwd,那当我们执行该命令时,会执行哪 一个?答案是第一优先执行 shell 内置的命令,再执行路 ...
- 让Mono 4在Raspberry Pi上飞
最近公司有项目想要在树莓派上做,代替原来的工控机(我们是把工控主机当作小的主机用,一台小的工控主机最少也要600左右,而树莓派只要200多).于是,公司买了一个Raspberry Pi B+和一个Ra ...