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有一点点影响,其他的几乎可以忽略不计。

 1  public class Model1
 2     {
 3         public int Sales1 { get; set; }
 4         public int Title1 { get; set; }
 5         public double Sales { get; set; }
 6         public string Title { get; set; }
 7         public string Author { get; set; }
 8         public decimal Price { get; set; }
 9         public string Store { get; set; }
10         public string Shipping { get; set; }
11         public string Bestseller { get; set; }
12         public DateTime Publication { get; set; }
13     }

  Expression Tree核心代码:Expression解析T的成员变量,配合反射创建T的实例,用Expression动态创建Lambda表达式得到T的属性值。

 1   private static Func<object, string, object> GenerateGetValue()
 2         {
 3             var type = typeof(T);
 4             var instance = Expression.Parameter(typeof(object), "instance");
 5             var memberName = Expression.Parameter(typeof(string), "memberName");
 6             var nameHash = Expression.Variable(typeof(int), "nameHash");
 7             var getHashCode = Expression.Assign(nameHash, Expression.Call(memberName, typeof(object).GetMethod("GetHashCode")));
 8             var switchEx = Expression.Switch(nameHash, Expression.Constant(null),
 9                 (from propertyInfo in type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public)
10                  let property = Expression.Property(Expression.Convert(instance, typeof(T)), propertyInfo.Name)
11                  let propertyHash = Expression.Constant(propertyInfo.Name.GetHashCode(), typeof(int))
12                  select Expression.SwitchCase(Expression.Convert(property, typeof(object)), propertyHash)).ToArray());
13
14             var methodBody = Expression.Block(typeof(object), new[] { nameHash }, getHashCode, switchEx);
15             return Expression.Lambda<Func<object, string, object>>(methodBody, instance, memberName).Compile();
16         }

  测试用例:用上面的泛型实例model1构造一个容量为10万个集合List<T>,至于T的属性值随便给他赛一些就可以了。

 1   public void TestMethod1()
 2         {
 3             var model = new List<Model1>();
 4             Stopwatch stopwatch = new Stopwatch();
 5             stopwatch.Start();
 6             for (int i = 0; i < 100000; i++)
 7             {
 8                 model.Add(new Model1
 9                 {
10                     Sales1 = 0,
11                     Title1 = 1,
12                     Sales = 33 + i,
13                     Title = "标题" + i,
14                     Shipping = "23",
15                     Author = "作者" + i,
16                     Store = "23",
17                     Bestseller = "0",
18                     Price = i,
19                     Publication = DateTime.Now
20                 });
21             }
22             stopwatch.Start();
23
24             var json = JsonConvert.SerializeObject(model);
25             stopwatch.Stop();
26
27             stopwatch.Stop();
28             Console.WriteLine(@"Json.NET按默认格式直接序列化100000个泛型对象耗时:" + stopwatch.ElapsedMilliseconds + @"毫秒");
29             stopwatch.Restart();
30             var reflectionJson = ListToJsonOfReflection<Model1>(model);
31             stopwatch.Stop();
32             Console.WriteLine(@"Reflection解析自定义拼接序列化100000个泛型对象耗时:" + stopwatch.ElapsedMilliseconds + @"毫秒");
33             stopwatch.Restart();
34             var expressionJson = ListToJsonOfExpression<Model1>(model);
35             stopwatch.Stop();
36             Console.WriteLine(@"Expression Tree解析自定义拼接序列化100000个泛型对象耗时:" + stopwatch.ElapsedMilliseconds + @"毫秒");
37
38         }

  顺便做个性能测试,当然JsonConvert.SerializeObject(List<T>)得到的是key和value的集合字符串,比本文所需要的自定义拼接的字符串多了key,所以没有什么可比性,只是顺带列出来而已。纯反射解析List<T>拼接和Expression Tree解析List<T>拼接得到的Json格式一模一样。很明显Expression Tree 配合反射在执行大量动作时性能比纯反射还要高很多。

 

时间: 2024-11-04 19:11:16

Reflection和Expression Tree解析泛型集合快速定制特殊格式的Json的相关文章

快速入门系列--CLR--03泛型集合

.NET中的泛型集合 在这里主要介绍常见的泛型集合,很多时候其并发时的线程安全性常常令我们担忧.因而简述下.NET并发时线程安全特性,其详情请见MSDN. 普通集合都不支持多重并发写操作 部分支持单线程写和并发读操作 同时.NET4添加了大量并发集合 首先介绍常见的泛型集合接口,其大部分都位于System.Collection.Generic命名空间. IEnumerable<T>,其可以获取一个IEnumerator<T>迭代器,如果从数据库的角度来看,前者是表,后者是游标,同时

机房重构——泛型集合

敲三层的时候就听师傅说过泛型,只不过当时没有特别的注意.当敲用户登录窗体时,我遇到这样的问题,就是我们需要经过验证输入的信息的正误之后才能登录或者不能登录.判断时,需要返回我们从数据库中查到的信息,那么问题就来了,如何返回呢? 一开始我一直用的是DataTable返回数据的,但是当去判断的时候我不知道如何下手了,按照以往的经验,我们可以使用table.rows()或table.field(),具体的实现方法可以自己试验一下.这种方法虽然可以实现,可是里面重复的内容太多了,尤其是每次使用一个字段时

vb.net环境下将DataTable转成泛型集合方法

背景 做机房收费系统的时候,遇到这样一个问题,将数据库表中的数据取出一行,将每个单元格中的内容填充到窗体 的文本框中.考虑到用DataReader获取结果的复杂性,我就用了泛型集合.可是这么一用却出现了如图所示的问 题. 问题一: 出现这种问题,是因为在DataTable转实体类型时表的字段类型和实体的字段类型不一致造成的. 这个也可以 这么说,中国人的孩子都随父姓,这是传统.但孩子随母姓,就有些不妥. 问题二: 数据库表中字段名和要转换的实体属性字段名不一致,导致转换后实体中depart为空值

ConvertHelper与泛型集合

在机房重构时,我们经常会用到ConvertHelper.它把从数据库中查询到的dateTable(也是一个临时表)转化为泛型,然后再填充到DataGridView控件中.ConvertHelper类有两点体现了面向对象的思想.一是因为它是经常被使用而被封装起来的类:二是因为它的返回值是泛型集合,泛型集合使存储数据时灵活而安全,也体现了面向对象的思想. ConvertHelper与sqlHelper 一开始接触ConvertHelper,以为它和sqlHelper一样,后来发现它们因为作用不同引用

普通集合和泛型集合的区别,哈希表和字典表的区别,队列和堆栈的区别以及堆和栈的区别。

普通集合和泛型集合的区别: 泛型集合与传统集合相比 类型更安全. 泛型集合无需装箱拆箱操作. 泛型的重要性. 泛型是未来五年的主流技术 ... 通常情况下,建议您使用泛型集合,因为这样可以获得类型安全的直接优点而不需要从基集合类型派生并实现类型特定的成员.此外,如果集合元素为值类型,泛型集合类型的性能通常优于对应的非泛型集合类型(并优于从非泛型基集合类型派生的类型),因为使用泛型时不必对元素进行装箱. 下面的泛型类型对应于现有的集合类型: List 是对应于 ArrayList 的泛型类. Di

机房收费系统重构(六)—泛型集合

      机房收费系统重构仍在进行,但是在进行过程中,也许数据类型的转换是永远也避不开的,今天我就来讲讲关于数据类型转换的问题!       在个人版机房收费系统中,在DAL层中,如果是增删改,是不需要返回参数的,返回值是Boolean,但是在查询中,需要有返回值,而且返回的是Dateset类型,所以在这里问题就来了.      如果在返回值过程中一直返回的是表的类型,也许就没有那么多麻烦的事情了,但是dateset使得系统具有了强耦合性,但是如果返回的是实体类呢!关于这点我也查了查资料,为什

C#重的数组、集合(ArrayList)、泛型集合(list&lt;T&gt;)三者比较及扩展延伸……

本来我只想总结下数组.集合(ArrayList).泛型集合(list<T>)三者的比较的,可以一写下来要扩展的知识点有点多了,只能写一个小的知识点列表了如下: 1.数组.集合(ArrayList).泛型集合(list<T>)三者的比较 2.接口 3.值类型和引用类型解析 4.泛型 5.接口和类的区别 6.重载和重写 7.虚方法和抽象方法 8.继承和多态 9.还有很多-- 由于小达刚开始写博客,还挺新鲜,所以进度应该不慢.留给大家一点东西,也不枉白敲一场代码.

C# 将list&lt;&gt;泛型集合 转化为 DataTable

使用案例:将页面easy ui 中datagrid表格中的数据,存成json字符串, 通过ajax和ashx传入C#将string类型的json字符串解析成list<>泛型集合, 由于业务需要,将本地sql不同表的数据和页面html的数据(通过webservice传入),放在一起处理数据. 转化方法: public class ListToDatatable { public ListToDatatable() { } public static DataTable ListToDataTab

使用Expression Tree构建动态LINQ查询

这篇文章介绍一个有意思的话题,也是经常被人问到的:如何构建动态LINQ查询?所谓动态,主要的意思在于查询的条件可以随机组合,动态添加,而不是固定的写法.这个在很多系统开发过程中是非常有用的. 我这里给的一个解决方案是采用Expression Tree来构建. 其实这个技术很早就有,在.NET Framework 3.5开始引入.之前也有不少同学写过很多不错的理论性文章.我自己当年学习这个,觉得最好的几篇文章是由"装配脑袋"同学写的.[有时间请仔细阅读这些入门指南,做点练习基本就能理解]