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

简单,是因为只有一个类

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

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

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

public class JsonBuilder
{
    protected StringBuilder Buff = new StringBuilder(4096);//字符缓冲区
    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

完整代码

 JsonBuilder

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

调用部分

测试下json格式

灵活扩展

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

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

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

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

真是超级简单的啦~~~

原文地址:https://www.cnblogs.com/DreamRecorder/p/10218598.html

时间: 2024-07-31 19:40:48

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

mobi.css 轻量灵活的CSS框架

Mobi.css是一个专用于手机的轻量灵活的CSS框架(基础教程qkxue.net). 介绍 1. 压缩后只有3.6kb,低于Skeleton, Pure.css , Bootstrap v4等. 2. 大量使用 flexbox,非常灵活,主页自定义样式少于10行. 3. 专用于手机,桌面显示手机界面(手机app开发ty300.com),侧边栏显示向左或向右滑动键. 入门 您可在此界面下载该应用,可通过dist/mobi.min.css压缩文件. 可通过npm安装: npm install --

Rocket Training: 一种提升轻量网络性能的训练方法 by leona

Rocket Training: 一种提升轻量网络性能的训练方法 参考博客: https://www.jianshu.com/p/ec28185510b7 https://blog.csdn.net/cskywit/article/details/78987500 https://mp.weixin.qq.com/s/UkqwPBYgYQuIB9_jGMt2QQ 论文及代码: paper: https://arxiv.org/abs/1708.04106 code: https://github

elasticsearch(4) 轻量搜索

一 空搜索 搜索API的最基础的形式是没有指定任何查询的空搜索 ,它简单地返回集群中所有索引下的所有文档: 示例 GET 127.0.0.1:9200/_search 响应 { "took": 166, "timed_out": false, "_shards": { "total": 10, "successful": 10, "skipped": 0, "failed&qu

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

Jquery作为一款优秀的JS框架,简单易用的特性就不必说了.在实际的开发过程中,使用JQ的AJAX函数调用WebService 的接口实现AJAX的功能也成了一种比较普遍的技术手段了.WebService接口的实现,通常都是由OOP语言实现的.所以 在WebService的接口函数中,难免可能会遇到除了简单数据类型的复杂数据类型.复杂的数据的数据类型机有可能是 WebService接口中的参数,也有可能是WebService的返回值.本文所叙述的要点为: 1.对于WebService接口复杂类

Bourbon – 简单、轻量的 Sass 混入库

Bourbon 是一个简单易用的 Sass 混入(Mixin)库,无需配置.该混入包含用于支持所有现代浏览器的 CSS3 属性前缀.前缀需要确保在旧的浏览器支持优雅降级.Bourbon 使用 SCSS 语法. 您可能感兴趣的相关文章 真是好东西!13种非常动感的页面加载动画效果 你见过吗?9款超炫的复选框(Checkbox)效果 超赞!基于 Bootstrap 的响应式的后台管理模板 太赞了!超炫的页面切换动画效果[附源码下载] 创意无限!一组网页边栏过渡动画[附源码下载] 立即下载      

OWIN轻量型框架介绍

OWIN轻量型框架介绍 阅读目录 引言 框架的特色 如何启动 各项功能 静态路由的3种写法 伪静态路由的支持 处理Form表单提交的文件 流式处理Post请求的数据 多种请求类型自动识别 响应处理 请求响应上下文 自定义默认处理函数 内置各种便捷函数 复合类型的请求处理 框架的扩展 静态内容的支持 跨域Post的支持 基础类型继承灵活处理 尾声 回到顶部 引言 什么是OWIN,我就不介绍了,请自行搜索,这里主要是介绍自行开发的OWIN框架的特点和用法.由于.NET的web框架都比较庞大,导致性能

Android轻量缓存框架--ASimpleCache

[转] 大神真面目 稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! 编辑推荐: 做Android应用开发的同学们相信对“缓存”这个词不陌生,缓存可能有多方面的概念,这里大概列举下程序开发的缓存大概有哪些: 1.服务端控制缓存 如volley请求库,便是通过服务端的“Cache-Control”和“max-age”来告诉客户端有没有缓存以及缓存的时间,也是推荐的使用

巧用命令行工具UCloud CLI,轻量操作API管理云资源

截止目前,UCloud已提供Python/Java/Golang等不同语言的API SDK.为进一步降低用户的运维人力投入,又推出了基于Golang SDK的命令行工具CLI(Command Line Interface),提供轻量化的API命令行调用方式,并在GitHub开源(https://github.com/ucloud/ucloud-cli).CLI的命令行交互方式更符合研发运维的操作习惯,并且一些典型使用场景通过CLI也更容易代码化的沉淀和维护. 下面是一些用户遇到的实际场景, 用C

轻量型ORM框架Dapper的使用

在真实的项目开发中,可能有些人比较喜欢写SQL语句,但是对于EF这种ORM框架比较排斥,那么轻量型的Dapper就是一个不错的选择,即让你写sql语句了,有进行了关系对象映射.其实对于EF吧,我说下我个人的见解,EF是相对来说比较重的ORM框架,它是讲究通用性的框架,而非单纯的实现某种需求的框架,不得不否认的说,EF的开发效率要比用单纯的ADO.NET写sql语句的效率高的不是一点半点,可能很多人会说EF的性能低等等,针对这种问题有时候是需要折中的来讲,从另一个方面来讲,你用了ADO.NET写s