学习笔记: Expression表达式目录树详解和扩展封装
1. 表达式目录树:语法树,或者说是一种数据结构;可以被我们解析
Func<int, int, int> func = (m, n) => m * n + 2;// new Func<int, int, int>((m, n) => m * n + 2);
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;//lambda表达式声明表达式目录树
//Expression<Func<int, int, int>> exp1 = (m, n) =>//只能一行 不能有大括号
// {
// return m * n + 2;
// };
//Queryable //a=>a.Id>3//表达式目录树:语法树,或者说是一种数据结构;可以被我们解析
int iResult1 = func.Invoke(12, 23);
int iResult2 = exp.Compile().Invoke(12, 23);//可以转换过去
编译后生成代码
即下面这段
ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "m"); //声明参数表达式
ParameterExpression parameterExpression2 = Expression.Parameter(typeof(int), "n");
var mutiply = Expression.Multiply(parameterExpression, parameterExpression2); //乘法表达式 m*n
var constant = Expression.Constant(2, typeof(int)); //常量表达式
var add = Expression.Add(mutiply, constant); //加法表达式Expression<Func<int, int, int>> expression = //组合
Expression.Lambda<Func<int, int, int>>(add, new ParameterExpression[] {
parameterExpression,
parameterExpression2
});
给出一个表达式 Expression<Func<People, bool>> lambda = x => x.Id.ToString().Equals("5");
自己拼装表达式目录树
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(People), "x");
var field = Expression.Field(parameterExpression, typeof(People).GetField("Id"));
var toString = typeof(People).GetMethod("ToString");
var toStringCall = Expression.Call(field, toString, new Expression[0]);
var equals = typeof(People).GetMethod("Equals");
var constant = Expression.Constant("5", typeof(string));
var equalsCall = Expression.Call(toStringCall, equals, new Expression[] { constant });
Expression<Func<People, bool>> expression =
Expression.Lambda<Func<People, bool>>(equalsCall, new ParameterExpression[]
{
parameterExpression
});expression.Compile().Invoke(new People()
{
Id = 11,
Name = "Eleven",
Age = 31
});
}
表达式目录树作用是什么呢
可以用来代替 反射 下面是 类型转换 测试反射与表达式树性能
static void Main(string[] args)
{
try
{{
Console.WriteLine("********************MapperTest********************");
ExpressionTest.MapperTest();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.Read();
}
/// <summary>
/// 认识/拼装 表达式目录树
/// 拼装表达式
/// 应用
/// </summary>
public class ExpressionTest
{
public static void MapperTest()
{
People people = new People()
{
Id = 11,
Name = "Eleven",
Age = 31
};long common = 0;
long generic = 0;
long cache = 0;
long reflection = 0;
long serialize = 0;
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1000000; i++)
{
PeopleCopy peopleCopy = new PeopleCopy()
{
Id = people.Id,
Name = people.Name,
Age = people.Age
};
}
watch.Stop();
common = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1000000; i++)
{
PeopleCopy peopleCopy = ReflectionMapper.Trans<People, PeopleCopy>(people);
}
watch.Stop();
reflection = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1000000; i++)
{
PeopleCopy peopleCopy = SerializeMapper.Trans<People, PeopleCopy>(people);
}
watch.Stop();
serialize = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1000000; i++)
{
PeopleCopy peopleCopy = ExpressionMapper.Trans<People, PeopleCopy>(people);
}
watch.Stop();
cache = watch.ElapsedMilliseconds;
}
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 1000000; i++)
{
PeopleCopy peopleCopy = ExpressionGenericMapper<People, PeopleCopy>.Trans(people);
}
watch.Stop();
generic = watch.ElapsedMilliseconds;
}Console.WriteLine($"common = { common} ms");
Console.WriteLine($"reflection = { reflection} ms");
Console.WriteLine($"serialize = { serialize} ms");
Console.WriteLine($"cache = { cache} ms");
Console.WriteLine($"generic = { generic} ms");}
}
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;
}public static TOut Trans1<TIn, TOut>(TIn tIn)
{
TOut tOut = Activator.CreateInstance<TOut>();
foreach (var prop in typeof(TOut).GetProperties())
{
var val = tIn.GetType().GetProperty(prop.Name).GetValue(tIn);
prop.SetValue(tOut, val);
}
foreach (var field in typeof(TOut).GetFields())
{
var val = tIn.GetType().GetField(field.Name).GetValue(tIn);
field.SetValue(tOut, val);
}
return tOut;
}}
/// <summary>
/// 使用第三方序列化反序列化工具
///
/// 还有automapper
/// </summary>
public class SerializeMapper
{
/// <summary>
/// 序列化反序列化方式
/// </summary>
/// <typeparam name="TIn"></typeparam>
/// <typeparam name="TOut"></typeparam>
public static TOut Trans<TIn, TOut>(TIn tIn)
{
return JsonConvert.DeserializeObject<TOut>(JsonConvert.SerializeObject(tIn));
}
}/// <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);
}
}
/// <summary>
/// 生成表达式目录树 泛型缓存
/// </summary>
/// <typeparam name="TIn"></typeparam>
/// <typeparam name="TOut"></typeparam>
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());
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);
}
}
/// <summary>
/// 实体类
/// </summary>
public class People
{
public int Age { get; set; }
public string Name { get; set; }public int Id;
}/// <summary>
/// 实体类Target
/// </summary>
public class PeopleCopy
{
public int Age { get; set; }
public string Name { get; set; }//ShortNamepublic int Id;
}
疑问点: 这个委托放在 静态字典 与 静态泛型缓存 为什么差了1个数量级
Dictionary<TKey, TValue>
维护一个哈希表。
它的枚举器将遍历散列表中的存储桶,直到找到一个非空的存储桶,然后返回该存储桶中的值。
一旦字典变大,这个操作变得昂贵。
而 泛型缓存 private static Func<TIn, TOut> _FUNC = null;
如果 TIn, TOut 类型有变动, 会导产生不同的副本.
简单描述下: TIn, TOut 类型有变动, 因为是泛型类 ExpressionGenericMapper<TIn, TOut>,会重新生成一个类, 并调用静态构造 给泛型缓存赋值, 变动前的泛型类,静态泛型缓存仍存在