[C#]自己动手写个ORM实现(4) 关于反射DataRow数据记录到实体性能的优化

总所周知,反射对于运行时确定对象类型十分方便,但是它最大的不足就是效率低下,比直接调用的效率慢了一百倍有余。

在3.5以前有codeDom或借助Emit直接编写IL来优化其效率,但是使用不便,借助3.5新增的Expression,让我们有了一种既简洁,在速度上又较反射有很大的提高。 示例如下


 1 public static T GetEntityByDataRowSlow<T>(this DataRow data) where T : new()
 2         {
 3             T t = new T();
 4             PropertyInfo[] properties = typeof(T).GetProperties();
 5 
 6             foreach (PropertyInfo p in properties)
 7             {
 8                 object value = data[p.Name] == DBNull.Value ? null : data[p.Name];
 9                 p.SetValue(t, value, null); 
10             }
11             return t;
12         }

 

如上,整段代码慢就慢在p.SetValue(t,value,null)这段上。 也有可能有人会说 typeof(T).GetProperties()获取所有属性应该缓存,但实际测试结果看下来影响并不大,效率相差无几。

接下来,主角登场了

 

 1 static Func<T, MethodInfo, objectobject> GetSetDelegate<T>(MethodInfo m,Type type)
 2         {
 3            
 4             var param_obj = Expression.Parameter(typeof(T), "obj");
 5             var param_val = Expression.Parameter(typeof(object), "val");
 6             var param_m = Expression.Parameter(typeof(MethodInfo), "m");
 7             var body_val = Expression.Convert(param_val, type);
 8             var body = Expression.Call(param_obj, m, body_val);
 9             Action<T, MethodInfo, object> set = Expression.Lambda<Action<T, MethodInfo, object>>(body, param_obj, param_m, param_val).Compile();
10             return (instance, method, v) =>
11             {
12                 set(instance, method, v);
13                 return null;
14             };
15         }

 

1 static void FastSetValue<T>(this PropertyInfo property,T t, object value)
2         {
3             MethodInfo m = property.GetSetMethod();
4             GetSetDelegate<T>(m,property.PropertyType)(t, m, value);
5         }

 

关于Expression和lambda的介绍可参看园里大牛赵哥的文章  方法的直接调用,反射调用与……Lambda表达式调用

经过改良的调用方法

 

 

public static T FastGetEntityByDataRow<T>(this DataRow data) where T : new()
        {
            T t 
= new T();
            PropertyInfo[] properties 
= GetProperties(typeof(T));
            
            
foreach (PropertyInfo p in properties)
            {                    
                
object value = data[p.Name] == DBNull.Value ? null : data[p.Name];
                p.FastSetValue
<T>(t, value);
            }
            
return t; 
        }

 

经过测试下来  如果直接是Entity.Property = "somevalue"设置属性的速度比值是1的话,反射的速度比值是100多,而经过改良的上述方法比值在2-3之间。

尽管这样,常见Web应用的主要瓶颈还是在结构的设计,数据库的读取,上面的方法对于整个程序框架的影响也只是积跬步,单用这个地方用了也几乎白用,不用白不用。谨记录一下。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏