很多项目都会用到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的更多相关文章

  1. C#利用 string.Join 泛型集合快速转换拼接字符串

    C#利用 string.Join 泛型集合快速转换拼接字符串 List<int> superior_list = new List<int>(); superior_list. ...

  2. 泛型集合、datatable常用数据类型转换Json帮助类

    泛型集合.datatable常用数据类型转换Json帮助类 using System; using System.Data; using System.Configuration; using Sys ...

  3. C#中利用LINQ to XML与反射把任意类型的泛型集合转换成XML格式字符串

    在工作中,如果需要跟XML打交道,难免会遇到需要把一个类型集合转换成XML格式的情况.之前的方法比较笨拙,需要给不同的类型,各自写一个转换的函数.但是后来接触反射后,就知道可以利用反射去读取一个类型的 ...

  4. node.js解析微信消息推送xml格式加密的消息

    之前写过一个解密json格式加密的,我以为xml的和json的差不多,是上上个星期五吧,我的同事也是在做微信公众号里面的消息推送解密,发现好像只能使用xml加密格式的发送到服务器,我们去年也做过企业微 ...

  5. WebAPI调用笔记 ASP.NET CORE 学习之自定义异常处理 MySQL数据库查询优化建议 .NET操作XML文件之泛型集合的序列化与反序列化 Asp.Net Core 轻松学-多线程之Task快速上手 Asp.Net Core 轻松学-多线程之Task(补充)

    WebAPI调用笔记   前言 即时通信项目中初次调用OA接口遇到了一些问题,因为本人从业后几乎一直做CS端项目,一个简单的WebAPI调用居然浪费了不少时间,特此记录. 接口描述 首先说明一下,基于 ...

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

    .NET中的泛型集合 在这里主要介绍常见的泛型集合,很多时候其并发时的线程安全性常常令我们担忧.因而简述下.NET并发时线程安全特性,其详情请见MSDN. 普通集合都不支持多重并发写操作 部分支持单线 ...

  7. 【C#表达式树 开篇】 Expression Tree - 动态语言

    .NET 3.5中新增的表达式树(Expression Tree)特性,第一次在.NET平台中引入了"逻辑即数据"的概念.也就是说,我们可以在代码里使用高级语言的形式编写一段逻辑, ...

  8. Expression Tree 扩展MVC中的 HtmlHelper 和 UrlHelper

    表达式树是LINQ To everything 的基础,同时各种类库的Fluent API也 大量使用了Expression Tree.还记得我在不懂expression tree时,各种眼花缭乱的A ...

  9. Expression Tree上手指南 (一)

    大家可能都知道Expression Tree是.NET 3.5引入的新增功能.不少朋友们已经听说过这一特性,但还没来得及了解.看看博客园里的老赵等诸多牛人,将Expression Tree玩得眼花缭乱 ...

随机推荐

  1. SQL Server调优系列基础篇(联合运算符总结)

    前言 上两篇文章我们介绍了查看查询计划的方式,以及一些常用的连接运算符的优化技巧,本篇我们总结联合运算符的使用方式和优化技巧. 废话少说,直接进入本篇的主题. 技术准备 基于SQL Server200 ...

  2. 烂泥:gpg加解密软件学习

    本文由ilanniweb提供友情赞助,首发于烂泥行天下 想要获得更多的文章,可以关注我的微信ilanniweb. 为什么要学习gpg呢?因为要在Linux下把一个邮箱的密码加密,不让其他人看到该邮箱真 ...

  3. DataTable去除重复行,根据某一字段进行distinct

    网上有很多方法,比如利用视图处理: //去掉重复行 DataView dv = table.DefaultView; table = dv.ToTable(true, new string[] { & ...

  4. dpdk在虚拟机上出错处理

    目录 1. 所用系统与软件版本 2. 虚拟机配置 3. Ubuntu 12.04上的配置 3.1 准备 3.2 通过setup脚本进行配置 3.3 通过命令配置 4. CentOS 7.0上的配置 4 ...

  5. [译] OpenStack Kilo 版本中 Neutron 的新变化

    OpenStack Kilo 版本,OpenStack 这个开源项目的第11个版本,已经于2015年4月正式发布了.现在是个合适的时间来看看这个版本中Neutron到底发生了哪些变化了,以及引入了哪些 ...

  6. [转]C# 连接 Oracle 的几种方式

    本文转自:http://www.cnblogs.com/storys/archive/2013/03/06/2945914.html 一:通过System.Data.OracleClient(需要安装 ...

  7. [转]Asp.net MVC使用Filter解除Session, Cookie等依赖

    本文转自:http://www.cnblogs.com/JustRun1983/p/3279139.html 本文,介绍了Filter在MVC请求的生命周期中的作用和角色,以及Filter的一些常用应 ...

  8. 网络之TCP/IP四层模型

    应用层(应用层.表示层.会话层):FTP.Telnet.DNS.SMTP 传输层(传输层):TCP<传输控制协议> . UDP<用户数据报文协议> 网际互连层(网络层):IP. ...

  9. ural 1208 Legendary Teams Contest

    题意描述:给定K支队伍,每队三个队员,不同队伍之间队员可能部分重复,输出这些队员同时能够组成多少完整的队伍: DFS,利用DFS深度优先搜索,如果该队所有队员都没有被访问过,那么将该队计入结果,再去选 ...

  10. Java之线程处理之二

    No.1编写一个打印机类 写两个方法 public class Printer { public void print1() { System.out.print("微"); Sy ...