因为项目中需要用到反射,而单纯反射据说性能很低,所以就想到了优化反射.而关于反射的优化方案园子里面有不少大牛都已经提出来详细的解决方案,这个就不详细说了,想了解的可以具体看这里http://www.cnblogs.com/fish-li/category/453548.html.文章里面提到了通过创建委托来提高反射性能.
既然有了解决方案,那就来吧.
项目中主要用反射来操作对象属性,所以就先不考虑方法的反射了
使用Emit构造委托
1 public delegate object FastGetMethod(object arg);//定义委托类型 2 public static class FastReflection 3 { 4 /// <summary> 5 /// 缓存委托集合 6 /// </summary> 7 private static ConcurrentDictionary<string, FastGetMethod> _getMethods = new ConcurrentDictionary<string, FastGetMethod>(); 8 public static FastGetMethod FastGetMethod(PropertyInfo property) 9 { 10 FastGetMethod getMethod; 11 if (!_getMethods.TryGetValue(string.Concat(property.DeclaringType.FullName, "_", property.Name), out getMethod)) 12 { 13 getMethod = FastReflection.GetGetMethod(property); 14 _getMethods.TryAdd(string.Concat(property.DeclaringType.FullName, "_", property.Name), getMethod); 15 } 16 return getMethod; 17 } 18 private static FastGetMethod GetGetMethod(PropertyInfo property) 19 { 20 if (property == null) 21 { 22 throw new ArgumentNullException("property"); 23 } 24 if (!property.CanRead) 25 { 26 return null; 27 } 28 MethodInfo method = property.GetGetMethod(true); 29 DynamicMethod dm = new DynamicMethod("GetValueMethod", typeof(object), new Type[] { typeof(object) }, property.DeclaringType, true); 30 ILGenerator il = dm.GetILGenerator(); 31 if (!method.IsStatic) 32 { 33 il.Emit(OpCodes.Ldarg_0); 34 il.EmitCall(OpCodes.Callvirt, method, null); 35 } 36 else 37 { 38 il.EmitCall(OpCodes.Call, method, null); 39 } 40 if (property.PropertyType.IsValueType) 41 { 42 il.Emit(OpCodes.Box, property.PropertyType); 43 } 44 il.Emit(OpCodes.Ret); 45 return (FastGetMethod)dm.CreateDelegate(typeof(FastGetMethod)); 46 } 47 }
如此,就来测试一下吧
测试代码如下
class Person { public string Name { get; set; } public int Age { get; set; } } //调用代码 Person p = new Person() { Age = 100, Name = "Hello Test" }; PropertyInfo info = (typeof(Person)).GetProperty("Age"); int times = 100 * 100 * 100;//调用1000000次 int temp1 = 0, temp2 = 0; Console.WriteLine("调用{0}次比较", times); Stopwatch watch1 = new Stopwatch(); watch1.Start(); FastGetMethod getMethod = FastReflection.FastGetMethod(info); for (int i = 0; i < times; i++) { temp1 = (int)getMethod(p); } watch1.Stop(); Console.WriteLine("FastReflection耗时:{0}", watch1.Elapsed); Stopwatch watch2 = new Stopwatch(); watch2.Start(); for (int i = 0; i < times; i++) { temp2 = (int)info.GetValue(p, null); } watch2.Stop(); Console.WriteLine("直接反射耗时:{0}",watch2.Elapsed);
在release模式下
可以看到性能上确实有了很大差别
到这里似乎就算是完了,可以突然想看看单次调用时性能上的差别有多少
结果却有点出乎意料,单次调用时优化的反而比不上未优化的,让人无法接受啊,是什么原因导致的呢?想到构建委托时要消耗性能,那就看下创建委托是需要的时间吧
可以看到构建委托时确实消耗不少性能,可是在接下来的调用还是有着巨大的差别,这是怎么一回事?单次调用直接反射有着巨大优势,可是在多次调用是反而要比通过委托来调用,这究竟是怎么一回事呢?这个让我很迷茫,这样做到底算不算的上是优化?一个项目中一次请求中可能只掉用几次反射,没有像测试这样一次性调用这么多次,那是否需要去反射呢?希望可以有高人帮忙解答下