Reflection和Expression Tree解析泛型集合快速定制特殊格式的Json
很多项目都会用到Json,而且大部分的Json都是格式固定,功能强大,转换简单等,标准的key,value集合字符串;直接JsonConvert.SerializeObject(List<T>)就可以搞定了,但凡事并非千篇一律,比如有的时候我们需要的Json可能只需要value,不需要key,并且前后可能还需要辅助信息等等,那该怎么办呢?我所能想到的可能有两种方案,1.自定义跟所需json格式一样的数据结构model,然后用JsonConvert.SerializeObject(model)直接得到;2.解析泛型集合再自定义拼接Json字符串。
自定义Json格式:Json格式比较灵活,可以随意定义,也可以无限嵌套,这里只取两层,所有的data和id构成rows的集合,其中data只取T的value,并且在data之前加一个id,所以这里的Json就相当于只有rows嵌套了data。

构造泛型T的一个实例:既然是泛型,那就具有通用性,所以这里随便构造一个model,除了字段的多少和数据类型对本反射和Expression有一点点影响,其他的几乎可以忽略不计。
public class Model1
{
public int Sales1 { get; set; }
public int Title1 { get; set; }
public double Sales { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public decimal Price { get; set; }
public string Store { get; set; }
public string Shipping { get; set; }
public string Bestseller { get; set; }
public DateTime Publication { get; set; }
}
Expression Tree核心代码:Expression解析T的成员变量,配合反射创建T的实例,用Expression动态创建Lambda表达式得到T的属性值。
public class ExpressionTreeProperty<T>
{
internal static Func<object, string, object> s_GetValue = null;
static ExpressionTreeProperty()
{
if (s_GetValue == null)
{
s_GetValue = GenerateGetValue();
}
}
public object GetValue(T instance, string memberName)
{
return s_GetValue(instance, memberName);
}
public object GetValue(object instance, string memberName)
{
return s_GetValue(instance, memberName);
}
private static Func<object, string, object> GenerateGetValue()
{
var type = typeof(T);
var instance = Expression.Parameter(typeof(object), "instance");
var memberName = Expression.Parameter(typeof(string), "memberName");
var nameHash = Expression.Variable(typeof(int), "nameHash");
var getHashCode = Expression.Assign(nameHash, Expression.Call(memberName, typeof(object).GetMethod("GetHashCode")));
var switchEx = Expression.Switch(nameHash, Expression.Constant(null),
(from propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
let property = Expression.Property(Expression.Convert(instance, typeof(T)), propertyInfo.Name)
let propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int))
select Expression.SwitchCase(Expression.Convert(property, typeof(object)), propertyHash)).ToArray());
var methodBody = Expression.Block(typeof(object), new[] { nameHash }, getHashCode, switchEx);
return Expression.Lambda<Func<object, string, object>>(methodBody, instance, memberName).Compile();
}
}
拼接Json字符串:
/// <summary>
/// Reflection解析List<T>拼接Json字符串
/// </summary>
public static string ListToJsonOfReflection<T>(IList<T> list)
{
var json = new StringBuilder(@"{ rows: [");
; i < list.Count; i++)
{
json.Append("{ id :");
json.Append(i + + ", data:[");
var pi = list[i].GetType().GetProperties();
foreach (var property in pi)
{
json.Append("\"" + property.GetValue(list[i], null) + "\",");
}
json = json.Remove(json.Length - , );
json.Append("]},");
}
json = json.Remove(json.Length - , );
json.Append("]}");
return json.ToString();
}
/// <summary>
/// Expression解析List<T>拼接Json字符串
/// </summary>
public static string ListToJsonOfExpression<T>(IList<T> list)
{
var json = new StringBuilder(@"{ rows: [");
var expressionTreeProperty= new ExpressionTreeProperty<Model1>();
; i < list.Count; i++)
{
var propertys = list[i].GetType().GetProperties();
json.Append("{ id :");
json.Append(i + + ", data:[");
foreach (var property in propertys)
{
json.Append("\"" + expressionTreeProperty.GetValue(list[i], property.Name) + "\",");
}
json = json.Remove(json.Length - , );
json.Append("]},");
}
json = json.Remove(json.Length - , );
json.Append("]}");
return json.ToString();
}
测试用例:用上面的泛型实例model1构造一个容量为10万个集合List<T>,至于T的属性值随便给他赛一些就可以了。
public void TestMethod1()
{
var model = new List<Model1>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
; i < ; i++)
{
model.Add(new Model1
{
Sales1 = ,
Title1 = ,
Sales = + i,
Title = "标题" + i,
Shipping = ",
Author = "作者" + i,
Store = ",
Bestseller = ",
Price = i,
Publication = DateTime.Now
});
}
stopwatch.Start();
var json = JsonConvert.SerializeObject(model);
stopwatch.Stop();
stopwatch.Stop();
Console.WriteLine(@"Json.NET按默认格式直接序列化100000个泛型对象耗时:" + stopwatch.ElapsedMilliseconds + @"毫秒");
stopwatch.Restart();
var reflectionJson = ListToJsonOfReflection<Model1>(model);
stopwatch.Stop();
Console.WriteLine(@"Reflection解析自定义拼接序列化100000个泛型对象耗时:" + stopwatch.ElapsedMilliseconds + @"毫秒");
stopwatch.Restart();
var expressionJson = ListToJsonOfExpression<Model1>(model);
stopwatch.Stop();
Console.WriteLine(@"Expression Tree解析自定义拼接序列化100000个泛型对象耗时:" + stopwatch.ElapsedMilliseconds + @"毫秒");
}
顺便做个性能测试,当然JsonConvert.SerializeObject(List<T>)得到的是key和value的集合字符串,比本文所需要的自定义拼接的字符串多了key,所以没有什么可比性,只是顺带列出来而已。纯反射解析List<T>拼接和Expression Tree解析List<T>拼接得到的Json格式一模一样。很明显Expression Tree 配合反射在执行大量动作时性能比纯反射还要高很多。

Reflection和Expression Tree解析泛型集合快速定制特殊格式的Json的更多相关文章
- C#利用 string.Join 泛型集合快速转换拼接字符串
C#利用 string.Join 泛型集合快速转换拼接字符串 List<int> superior_list = new List<int>(); superior_list. ...
- 泛型集合、datatable常用数据类型转换Json帮助类
泛型集合.datatable常用数据类型转换Json帮助类 using System; using System.Data; using System.Configuration; using Sys ...
- C#中利用LINQ to XML与反射把任意类型的泛型集合转换成XML格式字符串
在工作中,如果需要跟XML打交道,难免会遇到需要把一个类型集合转换成XML格式的情况.之前的方法比较笨拙,需要给不同的类型,各自写一个转换的函数.但是后来接触反射后,就知道可以利用反射去读取一个类型的 ...
- node.js解析微信消息推送xml格式加密的消息
之前写过一个解密json格式加密的,我以为xml的和json的差不多,是上上个星期五吧,我的同事也是在做微信公众号里面的消息推送解密,发现好像只能使用xml加密格式的发送到服务器,我们去年也做过企业微 ...
- WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)
WebAPI调用笔记 前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...
- 快速入门系列--CLR--03泛型集合
.NET中的泛型集合 在这里主要介绍常见的泛型集合,很多时候其并发时的线程安全性常常令我们担忧.因而简述下.NET并发时线程安全特性,其详情请见MSDN. 普通集合都不支持多重并发写操作 部分支持单线 ...
- 【C#表达式树 开篇】 Expression Tree - 动态语言
.NET 3.5中新增的表达式树(Expression Tree)特性,第一次在.NET平台中引入了"逻辑即数据"的概念.也就是说,我们可以在代码里使用高级语言的形式编写一段逻辑, ...
- Expression Tree 扩展MVC中的 HtmlHelper 和 UrlHelper
表达式树是LINQ To everything 的基础,同时各种类库的Fluent API也 大量使用了Expression Tree.还记得我在不懂expression tree时,各种眼花缭乱的A ...
- Expression Tree上手指南 (一)
大家可能都知道Expression Tree是.NET 3.5引入的新增功能.不少朋友们已经听说过这一特性,但还没来得及了解.看看博客园里的老赵等诸多牛人,将Expression Tree玩得眼花缭乱 ...
随机推荐
- spring 事务管理方式及配置
1.Spring声明式事务配置的五种方式 前段时间对Spring的事务配置做了比较深入的研究,在此之前对Spring的事务配置虽说也配置过,但是一直没有一个清楚的认识.通过这次的学习发觉Spring的 ...
- apache如何设置http自动跳转到https
如何设置http自动跳转到https?apache环境下,配置好https后,需要设置url重定向规则,使网站页面的http访问都自动转到https访问. 1.先打开url重定向支持1)打开Apach ...
- MongoDB学习笔记——Replica Set副本集
副本集 可以将MongoDB中的副本集看作一组服务器集群由一个主节点和多个副本节点等组成,相对于之前讲到的主从复制提供了故障自动转移的功能 副本集实现数据同步的方式依赖于local数据库中的oplog ...
- Angularjs之如何在跨域请求中传输Cookie
一般情况我们在使用WebApi之类的技术时,都会遇到跨域的问题,这个只需要在服务端做一下处理即可. 如果这些GET或POST请求不需要传递Cookie数据的话,就没什么问题了,但如果需要,那么会发现 ...
- MySQL调优系列基础篇
前言 有一段时间没有写博客了,整天都在忙,上班,录制课程,恰巧最近一段时间比较清闲,打算弄弄MYSQL数据库. 关于MySQL数据库,这里就不做过多的介绍,开源.免费等特性深受各个互联网行业喜爱,尤其 ...
- 跨应用程序域(AppDomain)的单例(Singleton)实现
转载自: 跨应用程序域(AppDomain)的单例(Singleton)实现 - CorePlex代码库 - CorePlex官方网站,Visual Studio插件,代码大全,代码仓库,代码整理,分 ...
- TeX Live安装配置等默认目录
TeX Live默认目录情况: TEXDIR (the main TeX directory): !! default location: /usr/local/texlive/2015 ...
- Sql server2012连接Sql server 2008时出现的问题:已成功与服务器建立连接,但在登陆过程中发生错误。(provider:SSL Provider,error:0-接收到的消息异常,或格式不正确。)
以前连接是正常的,就这两天连不上了.(没有耐心的直接看末尾解决办法) 错误消息如下: 1.尝试读取或写入受保护的内存.这通常指示其他内存已损坏.(System.Data) 2.已成功与服务器建立连接, ...
- POJ1094[有向环 拓扑排序]
Sorting It All Out Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 33184 Accepted: 11 ...
- Excel实用操作
目地 不能熟练操作Excel的程序员不是好策划. 一片区域填充相同数据 1.用鼠标框选一片区域,松开鼠标,不要点其它单元格 2.直接输入输入数据,输完之后,按Ctrl+Enter,选中的区域就会填充相 ...