C#简单实现表达式目录树(Expression)

2019-12-30 18:50:06丽君

有时候一些业务模型和实体模型不太一样,比如Student 于StudentDto实体的转换

一般的写法,new 一个实体然后把值赋给另一个实体,有一个就写一个,有十个就写是个,代码写死了,硬编码性能高


 {
     Student student = new Student() { Age = 12, Id=1, Name="晴天" };
     StudentDto studentDto = new StudentDto()
     {
      Name = student.Name,
      Id = student.Id,
      Age = student.Age
     };
    }

第二种:使用Expression表达式目录树


Expression<Func<Student, StudentDto>> lambda = p => new StudentDto
     {
      Age = p.Age,
      Id = p.Id,
      Name = p.Name
     };
     lambda.Compile().Invoke(student);

01.使用字典缓存表达式树,第一步是实例化了一个命令参数,parameterExpression,  List<MemberBinding> memberBindingList = new List<MemberBinding>();是一个对象成员集合列表,循环TOut的所有公共的属性和字段,Add到memberBindingList集合中,然后使用MemberInitExpression初始化多个对象拼装再调用。第一次调用动态拼装,组装了一个key放入字典中,缓存之后,就直接调用字典中的数据。缓存后的就是硬编码所以性能高。


 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq.Expressions;
 using System.Text;
 using System.Threading.Tasks;
 
 namespace ThreeHomeWork.MappingExtend
 {
  /// <summary>
  /// 生成表达式目录树。字典缓存
  /// </summary>
  public class ExpressionMapper
  {
   private static Dictionary<string, object> _DIC = new Dictionary<string, object>();
 
   /// <summary>
   /// 字典缓存表达式树
   /// </summary>
   /// <typeparam name="TIn"></typeparam>
   /// <typeparam name="TOut"></typeparam>
   /// <param name="tIn"></param>
   /// <returns></returns>
   public static TOut Trans<TIn, TOut>(TIn tIn)
   {
    string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
    if (!_DIC.ContainsKey(key))
    {
     ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
     List<MemberBinding> memberBindingList = new List<MemberBinding>();
     foreach (var item in typeof(TOut).GetProperties())
     {
      MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
      MemberBinding memberBinding = Expression.Bind(item, property);
      memberBindingList.Add(memberBinding);
     }
     foreach (var item in typeof(TOut).GetFields())
     {
      MemberExpression property = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
      MemberBinding memberBinding = Expression.Bind(item, property);
      memberBindingList.Add(memberBinding);
     }
     MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
     Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
     {
      parameterExpression
     });
     Func<TIn, TOut> func = lambda.Compile();//拼装是一次性的
     _DIC[key] = func;
    }
    return ((Func<TIn, TOut>)_DIC[key]).Invoke(tIn);
   }
 
  }
 }