作用
动态的将TIn对象赋值给TOut对象, 条件是TIn和TOut中的字段和属性相同
直接看代码
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text;
namespace 字典缓存表达式树
{
public class ExpressionMapper
{
//字典缓存
private static Dictionary<string, object> _Dic = new Dictionary<string, object>();
/// <summary>
/// 字典缓存表达式树
/// 作用:动态的将TIn对象赋值给TOut对象, 条件是TIn和TOut中的字段和属性相同
/// </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($"function_{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);//TOut.age = TIn.age赋值, 映射表达式
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);//TOut.age = TIn.age赋值
memberBindingList.Add(memberBinding);
}
MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());//初始化表达式
Expression<Func<TIn,TOut>> expression = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression,new ParameterExpression[] {
parameterExpression
});
Func<TIn, TOut> func = expression.Compile();
_Dic[key] = func;
}
return ((Func<TIn, TOut>)_Dic[key]).Invoke(tIn);
}
}
}
其中_Dic(字典缓存字段)的作用
它是静态变量,存储的是两个对象转化的委托实现。
分析
第一次调用该方法时,需要拼装表达式树。但第二次在调用时,_Dic字段里已经缓存了该委托方法,直接到Invoke(),实现一定的性能提升,并且是泛型的。
应用场景
用EF创建的数据库实体类,在查询数据时我们一般不会直接返回EF映射的实体类,我们一般会在创建一个字段内容相同的数据返回类。此时就可以用上述方法了。