表达式树常用在需要动态生成表达式的地方,比如将QueryPrameter对象动态的生成查询表达式,通过EF获取查询结果。
对表达式树的编写就是一个拼装过程,这点需要注意。
以下方法Map,动态的生成new一个对象的表达式。
Demo中使用该方法生成“Person对象转为DTO对象”的表达式。
namespace ConsoleDemo
{
class Program
{
static void Main(string[] args)
{
Person p2 = new Person()
{
Age = 5,
Name = "xx",
Gender = true,
};
var func = ExpressionHelper.Map<Person, Dto>();
Dto dto = func(p2);
Console.ReadKey();
}
}
public class Dto
{
public string Name1 { get; set; }
public int Age { get; set; }
public DateTime Birthday { get; set; }
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public bool Gender { get; set; }
}
public class ExpressionHelper
{
/// <summary>
/// 输出类型转换的表达式 i=>new o(){ member=i.prop }
/// </summary>
/// <typeparam name="Tin"></typeparam>
/// <typeparam name="Tout"></typeparam>
/// <returns></returns>
public static Func<Tin, Tout> Map<Tin, Tout>()
{
// 参数表达式i
var i = Expression.Parameter(typeof(Tin), "i");
//拼装成员赋值表达式 member=i.prop
List<MemberBinding> memberBindings = new List<MemberBinding>();
PropertyInfo[] Tout_props = typeof(Tout).GetProperties();
foreach (PropertyInfo prop in Tout_props)
{
//从输入类型中找对应的属性
PropertyInfo propertyInfo = typeof(Tin).GetProperty(prop.Name);
if (propertyInfo != null)
{
// i.prop
var i_prop = Expression.Property(i, propertyInfo);
// 赋值表达式 member=i.prop
var m__i_prop = Expression.Bind(prop, i_prop);
memberBindings.Add(m__i_prop);
}
}
// 创建对象表达式 new o(){ member=i.prop }
var new_o = Expression.MemberInit(Expression.New(typeof(Tout)), memberBindings);
// Lambda表达式 i=>new o(){ member=i.prop }
var lambda = Expression.Lambda<Func<Tin, Tout>>(new_o, i);
// 编译为委托
return lambda.Compile();
}
}
}