Fast Reflection Library

摘至:http://www.cnblogs.com/JeffreyZhao/archive/2009/02/01/Fast-Reflection-Library.html

基本使用方式
  反射是.NET中非常重要的功能。使用反射来构造对象、调用方法或是访问属性是某些项目中常用的做法之一(例如ORM框架)。众所周知,与一个成员的直接访问相比,反射调用的性能要低好几个数量级。FastReflectionLib提供了一种简便的方式,使一些常用反射调用的性能得到大幅提高。如下:

using System;using System.Reflection;using FastReflectionLib;namespace SimpleConsole{class Program{static void Main(string[] args)        {PropertyInfo propertyInfo = typeof(string).GetProperty("Length");MethodInfo methodInfo = typeof(string).GetMethod("Contains");string s = "Hello World!";// get value by normal reflectionint length1 = (int)propertyInfo.GetValue(s, null);// get value by the extension method from FastReflectionLib,            // which is much fasterint length2 = (int)propertyInfo.FastGetValue(s);// invoke by normal reflectionbool result1 = (bool)methodInfo.Invoke(s, new object[] { "Hello" });// invoke by the extension method from FastReflectionLib,            // which is much fasterbool result2 = (bool)methodInfo.FastInvoke(s, new object[] { "Hello" });        }    }}
  在得到了PropertyInfo或MethodInfo对象之后,我们可以使用GetValue或Invoke方法来访问属性或调用方法。在 FastReflectionLib中为PropertyInfo、MethodInfo等对象定义了对应的扩展方法,于是我们就可以使用这些扩展方法(从代码上看来,基本上只是在原来的方法之前加上“Fast”)来进行调用,与之前的方法相比,新的扩展方法性能有极大的提高。

直接使用各工作对象
  各FastXxx方法实际上是将PropertyInfo等对象作为Key去一个Cache中获取对应的工作对象,然后调用工作对象上对应的方法。因此,直接调用工作对象可以获得更好的性能。各工作对象类型的对应关系如下:

PropertyInfo:IPropertyAccessor
MethodInfo:IMethodInvoker
ConstructorInfo:IConstructorInvoker
FieldInfo:IFieldAccessor
  我们可以使用FastReflectionCaches.MethodInvokerCache来获取一个IMethodInvoker对象:

static void Execute(MethodInfo methodInfo, object instance, int times){ IMethodInvoker invoker = FastReflectionCaches.MethodInvokerCache.Get(methodInfo);object[] parameters = new object[0];for (int i = 0; i < times; i++)    {        invoker.Invoke(instance, parameters);    }}
工作对象的默认实现与扩展
  在FastReflectionLib中,已经提供了IPropertyAccessor等接口的默认实现。该实现将会构造一颗表达式树(Expression Tree)并将其编译(调用其Compile方法)以获得一个与反射方法签名相同的委托对象。这是一种简单、通用而安全的实现,由于Compile方法使用了Emit,其性能也较为令人满意(可见下面的性能测试)。但是这并不是性能最高的做法,如果使用Emit生成最优化的代码,其性能甚至会高于方法的直接调用(例如Dynamic Reflection Library)。如果您想使用更好的实现来替换,则可以自行构造一个工作对象接口的实现,并替换对应的Factory:

public class BetterPropertyAccessor : IPropertyAccessor{public BetterPropertyAccessor(PropertyInfo propertyInfo) { ... }    ...}public class BetterPropertyAccessorFactory :IFastReflectionFactory<PropertyInfo, IPropertyAccessor>{public IPropertyAccessor Create(PropertyInfo key)    {return new BetterPropertyAccessor(key);    }}class Program{static void Main(string[] args)    {FastReflectionFactories.PropertyAccessorFactory =new BetterPropertyAccessorFactory();        ...    }}
缓存的默认实现与扩展
  在FastReflectionLib中使用基于 System.Collections.Generic.Dictionary<TKey, TValue>类型编写的缓存容器。每次调用FastXxx扩展方法时,类库将从对应的缓存容器中获取工作对象。如果缓存容器中还没有所需的工作对象,那么它就会调用合适的Factory来构造新的工作对象。从下面的性能测试来看,许多时间是消耗在缓存查找上的,如果您有更好的缓存实现,可以使用以下的方法替换默认的缓存的容器:

public class BetterMethodInvokerCache :IFastReflectionCache<MethodInfo, IMethodInvoker>{public IMethodInvoker Get(MethodInfo key) { ... }}class Program{static void Main(string[] args)    {FastReflectionCaches.MethodInvokerCache = new BetterMethodInvokerCache();        ...    }}
根据需要自行缓存工作对象
  FastReflectionLib中通过PropertyInfo等对象作为Key,对PropertyAccessor等工作对象进行缓存。但是在某些场景下,您也可以选择合适的方式来自行缓存工作对象。与FastReflectionLib源码同时发布的CustomCache示例网站中包含了一个FastEval扩展,在某些场景下,我们可以使用这个更高效的方法来替换内置的Eval方法。这个示例的特点如下:

使用对象的类型和属性名同时作为缓存的Key获取对应的PropertyAccessor对象
使用PropertyAccessor获取“匿名对象”中的属性值
缓存的作用域为特定页面,而不是整个AppDomain。
性能测试
  FastReflectionLib源码中包含了一个性能测试项目,您可以从中看出FastReflectionLib对于反射的性能改进。摘录部分数据如下(测试在我的笔记本上运行,Release编译)。

  执行以下方法:

public class Test{public void MethodWithArgs(int a1, string a2) { }}
  进行一百万次调用,结果如下:

调用方式 消耗时间(秒)
方法直接调用 0.0071397
内置反射调用 1.4936181
工作对象调用 0.0468326
Fast方法调用 0.1373712

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值