Express 表达式目录树的应用
public class People
{
public int Age { get; set; }
public string Name { get; set; }
public int Id;
}
public class PeopleCopy
{
public int Age { get; set; }
public string Name { get; set; }
public int Id;
}
两个实体类之间的转换做法
PeopleCopy peopleCopy0 = new PeopleCopy() { Id = people.Id, Name = people.Name, Age = people.Age };
性能好,不灵活;不能共用;如果换成其他的类型就不能用了;
PeopleCopy peopleCopy1 = ReflectionMapper.Trans<People, PeopleCopy>(people); public class ReflectionMapper { /// <summary> /// 反射 /// </summary> /// <typeparam name="TIn"></typeparam> /// <typeparam name="TOut"></typeparam> /// <param name="tIn"></param> /// <returns></returns> public static TOut Trans<TIn, TOut>(TIn tIn) { TOut tOut = Activator.CreateInstance<TOut>(); foreach (var itemOut in tOut.GetType().GetProperties()) { var propIn = tIn.GetType().GetProperty(itemOut.Name); itemOut.SetValue(tOut, propIn.GetValue(tIn)); } foreach (var itemOut in tOut.GetType().GetFields()) { var fieldIn = tIn.GetType().GetField(itemOut.Name); itemOut.SetValue(tOut, fieldIn.GetValue(tIn)); } return tOut; } }
//反射 灵活,但是性能不好!
PeopleCopy peopleCopy2 = SerializeMapper.Trans<People, PeopleCopy>(people); public class SerializeMapper { /// <summary> /// 序列化反序列化方式 /// </summary> /// <typeparam name="TIn"></typeparam> /// <typeparam name="TOut"></typeparam> public static TOut Trans<TIn, TOut>(TIn tIn) { string strJson = JsonConvert.SerializeObject(tIn); return JsonConvert.DeserializeObject<TOut>(strJson); } }
//序列化,jason 、xml 灵活,但是性能不好!
Func<People, PeopleCopy> func = p => new PeopleCopy { Id = p.Id, Name = p.Name, Age = p.Age }; PeopleCopy peopleCopynew = func.Invoke(people);
灵活,但是性能不好!
如果能够把这个委托给缓存起来;根据我们的诉求,缓存一个委托;委托哪儿来?委托其实可以通过表达式目录树Compile一下,就可以得到一个委托;如果拼装一个表达式目录树,再Compile一下,然后缓存起来;就相当于拼装了这一组的转换逻辑;
拼装一下后,缓存下来,如果后面再需要使用,就可以直接使用这个委托了;
动态拼装转换过程;动态拼装了硬编码;
PeopleCopy peopleCopy = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
public class ExpressionGenericMapper<TIn, TOut>//Mapper`2
{
private static Func<TIn, TOut> _FUNC = null; //静态缓存
static ExpressionGenericMapper()
{
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());
//创建System.Linq.Expressions.MemberInitExpression
Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
{
parameterExpression
});
_FUNC = lambda.Compile();//拼装是一次性的
}
public static TOut Trans(TIn t)
{
return _FUNC(t);
}
也可以用字典缓存,性能不如上面的,会慢几倍
public class ExpressionMapper
{
/// <summary>
/// 字典缓存--hash分布 保存的是委托---委托内部是转换的动作;
/// </summary>
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 = $"funckey_{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);
}
}
PeopleCopy peopleCopy = ExpressionMapper.Trans<People, PeopleCopy>(people);