简单,是因为只有一个类

轻量,是因为整个类代码只有300行

灵活,是因为扩展方式只需要继承重写某个方法即可

补充:修正无法处理可空值类型的bug

首先我将这个类称之为JsonBuilder,我希望它以StringBuilder的方式来实现Json字符串的转换

public class JsonBuilder
{
protected StringBuilder Buff = new StringBuilder();//字符缓冲区
public string ToJsonString(object obj)
{
.......
return Buff.ToString();
}
.......
}

然后我为希望为每一个基础类型单独完成一个方法,并且方法可以被重写

protected virtual void AppendByte(Byte value)
protected virtual void AppendDecimal(Decimal value)
protected virtual void AppendInt16(Int16 value)
protected virtual void AppendInt32(Int32 value)
protected virtual void AppendInt64(Int64 value)
protected virtual void AppendSByte(SByte value)
protected virtual void AppendUInt16(UInt16 value)
protected virtual void AppendUInt32(UInt32 value)
protected virtual void AppendUInt64(UInt64 value)
protected virtual void AppendBoolean(Boolean value)
protected virtual void AppendChar(Char value)
protected virtual void AppendString(String value)
protected virtual void AppendDateTime(DateTime value)
protected virtual void AppendGuid(Guid value)
protected virtual void AppendDouble(Double value)
protected virtual void AppendSingle(Single value)
protected virtual void AppendEnum(Enum value)

为了使子类重写时更方便,我将数字类型合并为一个

protected virtual void AppendNumber(IConvertible number)

但仍然保留原有方法,只是原有方法直接调用AppendNumber,就像这样

protected virtual void AppendByte(Byte value) { AppendNumber(value); }
protected virtual void AppendDecimal(Decimal value) { AppendNumber(value); }
protected virtual void AppendInt16(Int16 value) { AppendNumber(value); }
protected virtual void AppendInt32(Int32 value) { AppendNumber(value); }
protected virtual void AppendInt64(Int64 value) { AppendNumber(value); }
protected virtual void AppendSByte(SByte value) { AppendNumber(value); }
protected virtual void AppendUInt16(UInt16 value) { AppendNumber(value); }
protected virtual void AppendUInt32(UInt32 value) { AppendNumber(value); }
protected virtual void AppendUInt64(UInt64 value) { AppendNumber(value); }
protected virtual void AppendDouble(Double value) { AppendNumber(value); }
protected virtual void AppendSingle(Single value) { AppendNumber(value); }

这样的好处是我可以在子类中灵活的选择重写全部的数字类型,还是只重写某种特定类型

然后接着,我需要完成一些已知类型的转换方法,比如数组,集合,字典,数据表等等

protected virtual void AppendArray(IEnumerable array)//数组,集合
protected virtual void AppendJson(IDictionary dict)//字典
protected virtual void AppendDataSet(DataSet dataset)//数据表集
protected virtual void AppendDataTable(DataTable table)//单表
protected virtual void AppendDataView(DataView view)//表视图

 ps:这些方法,单个实现都不困难,限于篇幅问题,这里就不介绍了,最后会放出完整代码

已知类型处理完后,再添加一个对未知类型的处理方法,这里我用的是最基本的反射

protected virtual void AppendOther(object obj)
{
Type t = obj.GetType();
Buff.Append('{');
string fix = "";
foreach (var p in t.GetProperties())
{
if (p.CanRead)
{
Buff.Append(fix);
AppendKey(p.Name, false);
object value = p.GetValue(obj, null);
AppendObject(value);
fix = ",";
}
}
Buff.Append('}');
}

实际上有2个方法是目前为止不存在的

现在我们把他加上

/// <summary> 追加Key
/// </summary>
/// <param name="key"></param>
/// <param name="escape">key中是否有(引号,回车,制表符等)特殊字符,需要转义</param>
protected virtual void AppendKey(string key, bool escape)
{
if (escape)
{
AppendString(key);
}
else
{
Buff.Append('"');
Buff.Append(key);
Buff.Append('"');
}
Buff.Append(':');
}
private Dictionary<object, object> _LoopObject = new Dictionary<object, object>();//循环引用对象缓存区
//泛对象
protected void AppendObject(object obj)
{
if (obj == null) Buff.Append("null");else if (obj is String) AppendString((String)obj);
else if (obj is Int32) AppendInt32((Int32)obj);
else if (obj is Boolean) AppendBoolean((Boolean)obj);
else if (obj is DateTime) AppendDateTime((DateTime)obj);
else if (obj is Double) AppendDouble((Double)obj);
else if (obj is Enum) AppendEnum((Enum)obj);
else if (obj is Decimal) AppendDecimal((Decimal)obj)  ;
else if (obj is Char) AppendChar((Char)obj);
else if (obj is Single) AppendSingle((Single)obj);
else if (obj is Guid) AppendGuid((Guid)obj);
else if (obj is Byte) AppendByte((Byte)obj);
else if (obj is Int16) AppendInt16((Int16)obj);
else if (obj is Int64) AppendInt64((Int64)obj);
else if (obj is SByte) AppendSByte((SByte)obj);
else if (obj is UInt32) AppendUInt32((UInt32)obj);
else if (obj is UInt64) AppendUInt64((UInt64)obj);
else if (_LoopObject.ContainsKey(obj) == false)
{
_LoopObject.Add(obj, null);
if (obj is IDictionary) AppendJson((IDictionary)obj);
else if (obj is IEnumerable) AppendArray((IEnumerable)obj);
else if (obj is DataSet) AppendDataSet((DataSet)obj);
else if (obj is DataTable) AppendDataTable((DataTable)obj);
else if (obj is DataView) AppendDataView((DataView)obj);
else AppendOther(obj);
_LoopObject.Remove(obj);
}
else
{
Buff.Append("undefined");
}
}

这2个方法都比较好理解,

一个是用来处理Key的,这里预留了一个参数escape,是为了性能的一些考虑,比如反射时的属性名称,这个是绝对不可能出现一些特殊符号的,所以可以直接作为Json的Key使用

另一个方法是用来作为泛对象(不是泛型对象)的入口方法,所有对象通过这个方法都可以找到对应的处理方法

还有一个对象_LoopObject,这个对象是为了解决循环引用的问题的,比如常用的对象Page(当然没有人会把这个对象转为Json,这里只是用来做说明)中就有一个Page的属性,指向this,如果没有额外的处理,解析将会进入一个循环递归,直到栈溢出(目前已知的几个第三方组件对这个情况的支持都不好,都会抛出异常,这个以后的文章会详细说明),而我这里做的处理是将这种无法解析循环引用对象都返回undefined,也正好可以区别于空对象的null

完整代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Text; namespace blqw
{
/// <summary> 用于将C#转换为Json字符串
/// </summary>
public class JsonBuilder
{
private Dictionary<object, object> _LoopObject = new Dictionary<object, object>();//循环引用对象缓存区
protected StringBuilder Buff = new StringBuilder();//字符缓冲区 public string ToJsonString(object obj)
{
Buff.Length = ;
AppendObject(obj);
return Buff.ToString();
}
//泛对象
protected void AppendObject(object obj)
{
if (obj == null) Buff.Append("null");
else if (obj is String) AppendString((String)obj);
else if (obj is Int32) AppendInt32((Int32)obj);
else if (obj is Boolean) AppendBoolean((Boolean)obj);
else if (obj is DateTime) AppendDateTime((DateTime)obj);
else if (obj is Double) AppendDouble((Double)obj);
else if (obj is Enum) AppendEnum((Enum)obj);
else if (obj is Decimal) AppendDecimal((Decimal)obj);
else if (obj is Char) AppendChar((Char)obj);
else if (obj is Single) AppendSingle((Single)obj);
else if (obj is Guid) AppendGuid((Guid)obj);
else if (obj is Byte) AppendByte((Byte)obj);
else if (obj is Int16) AppendInt16((Int16)obj);
else if (obj is Int64) AppendInt64((Int64)obj);
else if (obj is SByte) AppendSByte((SByte)obj);
else if (obj is UInt32) AppendUInt32((UInt32)obj);
else if (obj is UInt64) AppendUInt64((UInt64)obj);
else if (_LoopObject.ContainsKey(obj) == false)
{
_LoopObject.Add(obj, null);
if (obj is IDictionary) AppendJson((IDictionary)obj);
else if (obj is IEnumerable) AppendArray((IEnumerable)obj);
else if (obj is DataSet) AppendDataSet((DataSet)obj);
else if (obj is DataTable) AppendDataTable((DataTable)obj);
else if (obj is DataView) AppendDataView((DataView)obj);
else AppendOther(obj);
_LoopObject.Remove(obj);
}
else
{
Buff.Append("undefined");
}
}
protected virtual void AppendOther(object obj)
{
Type t = obj.GetType();
Buff.Append('{');
string fix = "";
foreach (var p in t.GetProperties())
{
if (p.CanRead)
{
Buff.Append(fix);
AppendKey(p.Name, false);
object value = p.GetValue(obj, null);
AppendObject(value);
fix = ",";
}
}
Buff.Append('}');
}
/// <summary> "
/// </summary>
public const char Quot = '"';
/// <summary> :
/// </summary>
public const char Colon = ':';
/// <summary> ,
/// </summary>
public const char Comma = ',';
/// <summary> 追加Key
/// </summary>
/// <param name="key"></param>
/// <param name="escape">key中是否有(引号,回车,制表符等)特殊字符,需要转义</param>
protected virtual void AppendKey(string key, bool escape)
{
if (escape)
{
AppendString(key);
}
else
{
Buff.Append(Quot);
Buff.Append(key);
Buff.Append(Quot);
}
Buff.Append(Colon);
}
//基本类型转换Json字符串写入Buff
protected virtual void AppendByte(Byte value) { AppendNumber(value); }
protected virtual void AppendDecimal(Decimal value) { AppendNumber(value); }
protected virtual void AppendInt16(Int16 value) { AppendNumber(value); }
protected virtual void AppendInt32(Int32 value) { AppendNumber(value); }
protected virtual void AppendInt64(Int64 value) { AppendNumber(value); }
protected virtual void AppendSByte(SByte value) { AppendNumber(value); }
protected virtual void AppendUInt16(UInt16 value) { AppendNumber(value); }
protected virtual void AppendUInt32(UInt32 value) { AppendNumber(value); }
protected virtual void AppendUInt64(UInt64 value) { AppendNumber(value); }
protected virtual void AppendDouble(Double value) { AppendNumber(value); }
protected virtual void AppendSingle(Single value) { AppendNumber(value); }
protected virtual void AppendBoolean(Boolean value) { Buff.Append(value ? "true" : "false"); }
protected virtual void AppendChar(Char value)
{
Buff.Append(Quot);
switch (value)
{
case '\\':
case '\n':
case '\r':
case '\t':
case '"':
Buff.Append('\\');
break;
}
Buff.Append(value);
Buff.Append(Quot);
}
protected virtual void AppendString(String value)
{
Buff.Append(Quot); for (int j = ; j < value.Length; j++)
{
switch (value[j])
{
case '\\':
case '\n':
case '\r':
case '\t':
case '"':
Buff.Append('\\');
break;
}
Buff.Append(value[j]);
} Buff.Append(Quot);
}
protected virtual void AppendDateTime(DateTime value)
{
Buff.Append(Quot);
if (value.Year < )
{
if (value.Year < )
{
if (value.Year < )
{
Buff.Append("");
}
else
{
Buff.Append("");
}
}
else
{
Buff.Append("");
}
}
Buff.Append(value.Year)
.Append('-');
if (value.Month < )
{
Buff.Append('');
}
Buff.Append(value.Month).Append('-'); if (value.Day < )
{
Buff.Append('');
}
Buff.Append(value.Day).Append(' '); if (value.Hour < )
{
Buff.Append('');
}
Buff.Append(value.Hour).Append(Colon); if (value.Minute < )
{
Buff.Append('');
}
Buff.Append(value.Minute).Append(Colon); if (value.Second < )
{
Buff.Append('');
}
Buff.Append(value.Second).Append(Quot);
}
protected virtual void AppendGuid(Guid value)
{
Buff.Append(Quot).Append(value.ToString()).Append(Quot);
}
//枚举
protected virtual void AppendEnum(Enum value)
{
Buff.Append(Quot).Append(value.ToString()).Append(Quot);
}
protected virtual void AppendNumber(IConvertible number)
{
Buff.Append(number.ToString(System.Globalization.NumberFormatInfo.InvariantInfo));
}
//转换数组对象
protected virtual void AppendArray(IEnumerable array)
{
Buff.Append('[');
var ee = array.GetEnumerator();
if (ee.MoveNext())
{
AppendObject(ee.Current);
while (ee.MoveNext())
{
Buff.Append(Comma);
AppendObject(ee.Current);
}
}
Buff.Append(']');
}
//转换键值对对象
protected virtual void AppendJson(IDictionary dict)
{
AppendJson(dict.Keys, dict.Values);
}
//分别有键值枚举的对象
protected virtual void AppendJson(IEnumerable keys, IEnumerable values)
{
Buff.Append('{');
var ke = keys.GetEnumerator();
var ve = values.GetEnumerator();
if (ke.MoveNext() && ve.MoveNext())
{
AppendKey(ke.Current + "", true);
AppendObject(ve.Current);
while (ke.MoveNext() && ve.MoveNext())
{
Buff.Append(Comma);
AppendKey(ke.Current + "", true);
AppendObject(ve.Current);
}
}
Buff.Append('}');
} protected virtual void AppendArray(IEnumerable enumer, Converter<object, object> getVal)
{
Buff.Append('[');
var ee = enumer.GetEnumerator();
if (ee.MoveNext())
{
AppendObject(ee.Current);
while (ee.MoveNext())
{
Buff.Append(Comma);
AppendObject(getVal(ee.Current));
}
}
Buff.Append(']');
} protected virtual void AppendJson(IEnumerable enumer, Converter<object, string> getKey, Converter<object, object> getVal, bool escapekey)
{
Buff.Append('{'); var ee = enumer.GetEnumerator();
if (ee.MoveNext())
{
AppendKey(getKey(ee.Current), escapekey);
AppendObject(getVal(ee.Current));
while (ee.MoveNext())
{
Buff.Append(Comma);
AppendKey(getKey(ee.Current), true);
AppendObject(getVal(ee.Current));
}
}
Buff.Append('}');
} protected virtual void AppendDataSet(DataSet dataset)
{
Buff.Append('{');
var ee = dataset.Tables.GetEnumerator();
if (ee.MoveNext())
{
DataTable table = (DataTable)ee.Current;
AppendKey(table.TableName, true);
AppendDataTable(table);
while (ee.MoveNext())
{
Buff.Append(Comma);
table = (DataTable)ee.Current;
AppendKey(table.TableName, true);
AppendDataTable(table);
}
}
Buff.Append('}');
} protected virtual void AppendDataTable(DataTable table)
{
Buff.Append("{\"columns\":");
AppendArray(table.Columns, o => ((DataColumn)o).ColumnName);
Buff.Append(",\"rows\":");
AppendArray(table.Rows, o => ((DataRow)o).ItemArray);
Buff.Append('}');
} protected virtual void AppendDataView(DataView tableView)
{
Buff.Append("{\"columns\":");
AppendArray(tableView.Table.Columns, o => ((DataColumn)o).ColumnName);
Buff.Append(",\"rows\":");
AppendArray(tableView, o => ((DataRowView)o).Row.ItemArray);
Buff.Append('}');
}
}
}

JsonBuilder

完整代码中有部分代码做了调整

调用部分

测试下json格式

灵活扩展

例如 上面的栗子中,枚举转出的是他的字符串形式

如果现在我需要把所有枚举转为对应的数字怎么做呢?

public class EnumValueJsonBuilder : JsonBuilder
{
protected override void AppendEnum(Enum value)
{
Buff.Append(value.GetHashCode());
}
}

新建一个类,然后重载AppendEnum就可以了

真是超级简单的啦~~~

.

.

.

.

.

不过,如果你以为这样就结束了,那么你就大错特错了

现在才刚刚开始.....未完待续....

一种简单,轻量,灵活的C#对象转Json对象的方案的更多相关文章

  1. 一种简单,轻量,灵活的C#对象转Json对象的方案(续)

    本文参考资料 一种简单,轻量,灵活的C#对象转Json对象的方案 [源码]Literacy 快速反射读写对象属性,字段 一段废话 之前我已经介绍了这个方案的名称为JsonBuilder,这套方案最大的 ...

  2. flutter最简单轻量便捷的路由管理方案NavRouter

    大家好,我是CrazyQ1,今天给大家推荐一个路由管理方案,用的非常不错的,叫nav_router. 项目地址是:https://github.com/fluttercandies/nav_route ...

  3. Bourbon – 简单轻量的 Sass 混入(Mixins)库

    Bourbon 是一个简单易用的 Sass 混入(Mixin)库,无需配置.该混入包含用于支持所有现代浏览器的 CSS3 属性前缀.前缀需要确保在旧的浏览器支持优雅降级.Bourbon 使用 SCSS ...

  4. quilljs 一款简单轻量的富文本编辑器(适合移动端)

    quilljs入门使用教程: quill.js是一款强大的现代富文本编辑器插件.该富文本编辑器插件支持所有的现代浏览器.平板电脑和手机.它提供了文本编辑器的所有功能,并为开发者提供大量的配置参数和方法 ...

  5. elasticsearch(4) 轻量搜索

    一 空搜索 搜索API的最基础的形式是没有指定任何查询的空搜索 ,它简单地返回集群中所有索引下的所有文档: 示例 GET 127.0.0.1:9200/_search 响应 { , "tim ...

  6. C# WebService的简单和复杂参数类型和结果的JSON格式

    Jquery作为一款优秀的JS框架,简单易用的特性就不必说了.在实际的开发过程中,使用JQ的AJAX函数调用WebService 的接口实现AJAX的功能也成了一种比较普遍的技术手段了.WebServ ...

  7. Prezento – 轻量、简单的 jQuery 幻灯片插件

    Prezento 是一个超级简单的 jQuery 幻灯片插件.可以让你网页以新颖的交互方式呈现.另外,Prezento 支持响应式设计,配置项也很灵活,可以根据你需要的效果配置. 您可能感兴趣的相关文 ...

  8. 轻量简单好用的C++JSON库CJsonObject

    1. JSON概述 JSON: JavaScript 对象表示法( JavaScript Object Notation) .是一种轻量级的数据交换格式. 它基于ECMAScript的一个子集.许多编 ...

  9. .Net轻量状态机Stateless的简单应用

    对于大部分系统中流程的变更,是十分正常的事情,小到一个状态的切换,大到整个系统都是围绕业务流再走,复杂点的有工作流引擎,简单点的几个if/else收工,但是往往有那种,心有余而力不足的,比简单复杂,比 ...

随机推荐

  1. 前端极易被误导的css选择器权重计算及css内联样式的妙用技巧

    记得大学时候,专业课的网页设计书籍里面讲过css选择器权重的计算:id是100,class是10,html标签是5等等,然后全部加起来的和进行比较... 我只想说:真是误人子弟,害人不浅! 最近,在前 ...

  2. node服务的监控预警系统架构

    需求背景 目前node端的服务逐渐成熟,在不少公司内部也开始承担业务处理或者视图渲染工作.不同于个人开发的简单服务器,企业级的node服务要求更为苛刻: 高稳定性.高可靠性.鲁棒性以及直观的监控和报警 ...

  3. ubuntu系统下如何修改host

    Ubuntu系统的Hosts只需修改/etc/hosts文件,在目录中还有一个hosts.conf文件,刚开始还以为只需要修改这个就可以了,结果发现是需要修改hosts.修改完之后要重启网络.具体过程 ...

  4. DDD 领域驱动设计-谈谈 Repository、IUnitOfWork 和 IDbContext 的实践(3)

    上一篇:<DDD 领域驱动设计-谈谈 Repository.IUnitOfWork 和 IDbContext 的实践(2)> 这篇文章主要是对 DDD.Sample 框架增加 Transa ...

  5. 用神奇的currentColor制作简洁的颜色动画效果

    先上一个兼容性总结图:老版本ie可以直接用复杂方法了,套用某表情包的话:  2016年了,做前端你还考虑兼容IE6?你这简直是自暴自弃! 好了,知道了兼容性,我们可以放心的使用了. 在CSS3中扩展了 ...

  6. Spark踩坑记——数据库(Hbase+Mysql)

    [TOC] 前言 在使用Spark Streaming的过程中对于计算产生结果的进行持久化时,我们往往需要操作数据库,去统计或者改变一些值.最近一个实时消费者处理任务,在使用spark streami ...

  7. C#中Length和Count的区别(个人观点)

    这篇文章将会很短...短到比你的JJ还短,当然开玩笑了.网上有说过Length和count的区别,都是很含糊的,我没有发现有 文章说得比较透彻的,所以,虽然这篇文章很短,我还是希望能留在首页,听听大家 ...

  8. C#各种同步方法 lock, Monitor,Mutex, Semaphore, Interlocked, ReaderWriterLock,AutoResetEvent, ManualResetEvent

    看下组织结构: System.Object System.MarshalByRefObject System.Threading.WaitHandle System.Threading.Mutex S ...

  9. 多线程同步工具——Lock

    本文原创,转载请注明出处. 参考文章: <"JUC锁"03之 公平锁(一)> <"JUC锁"03之 公平锁(二)> 锁分独占锁与共享锁, ...

  10. Java程序员应该了解的10个面向对象设计原则

    面向对象设计原则: 是OOPS(Object-Oriented Programming System,面向对象的程序设计系统)编程的核心,但大多数Java程序员追逐像Singleton.Decorat ...