.NET比较表达式树对性能影响
原题:日常应用中我们常常会和一些数据实体类打交道。现在假设我们的数据实体类里面定义了许多public的属性。请用Expression Tree实现一个动态逻辑,可以更新任意一种数据实体类的集合,比如List<Book>, List<Employee>等等中每一个元素的指定属性。比如我要对一个集合中所有Book元素的Author属性进行更新,您的程序就可以这样调用:
List<Book> books = …
SetAllProperty(books, “Author”, “Ninputer”);
当然您写的方法不知道Book类型,也不知道我要更新哪个属性,它应该能动态地支持任意的实体类集合。
首先我想到的就是遍历实体的属性,找对就修改的属性,然后调用SetValue方式就OK,代码也不多,如下:
{
if (null == t||null ==propertyName ||null ==propertyValue )
{
return null ;
}
for (int i = 0; i < t.Count; i++)
{
PropertyInfo[] proAs = t[i].GetType().GetProperties();
foreach (PropertyInfo proA in proAs)
{
if (!proA.CanRead &&!proA .CanWrite ) continue;
if (proA.Name.ToLower()==propertyName .ToString ().ToLower ())
{
proA.SetValue(t[i], propertyValue , null);
}
}
}
return t;
}
问题:上面的代码理论上和实际操作上都能够很好的完成练习题,但有个性能问题,如果这个实体集特别大的时候,比如一百万或者更多,此时就会特别耗时。于时我在脑袋的指点下,花了大半天时间终于有所结果:
版本一:结果都是正确的,问题时,这种写法比遍历属性赋值方式更慢。问题就在于LambdaExpression lambda = Expression.Lambda(call, parameter, value);var exp = lambda.Compile();这两条语句上,这个表达式经过Compile()后会生成一个Delegate,Compile方法在内部使用了Emit,而问题就出了DynamicInvoke上面,DynamicInvoke方法其本质与反射调用差不多。
{
ParameterExpression parameter = Expression.Parameter(typeof(T), "x");
ParameterExpression value = Expression.Parameter(typeof(string ), "propertyValue");
MethodInfo setter = typeof(T).GetMethod("set_"+propertyName );
MethodCallExpression call = Expression.Call(parameter, setter, value);
LambdaExpression lambda = Expression.Lambda(call, parameter, value);
var exp = lambda.Compile();
for (int i = 0; i < collection.Count; i++)
{
exp.DynamicInvoke(collection[i], propertyValue);
}
return collection;
}
- 上一篇:C#农历计算查询(公历与农历之间转换)
- 下一篇:.net剪切图片源码