C#中几种反射机制的比较
2015-02-20 22:02
281 查看
1. 前言
反射是一项很有趣的技术,她提供了另一个视角来模糊、统一地看待我们用代码搭建起来的小世界。由于之前工作的关系,小鱼酱曾用C++初略地实现过一套反射系统,用来支持游戏中属性编辑器的开发,在C++中反射是一项注入式或者后生成的一种编程方式,会导致代码难以阅读,脱离语言的美感。但在C#中的反射却是自然而优雅。因为最近在做手游开发的缘故,开始研究unity3D,开始重拾久违的C#。于是下面小鱼酱将简单介绍一下C#中的反射技术,并通过函数调用的角度来比较一下各个方式的性能。
2. 几种反射机制
2.1. 原生反射
C#通过System.Reflection程序集提供出了强大完整的反射功能,使我们可以在程序运行期获得“程序集”、“模块”、“类型”等信息,同时她也提供出了一种通用的方式的来访问与使用这些信息。于是我们在代码的世界中,面对不同的“人”或“物”,就有了不卑不亢的同一种腔调。在这里我们只讨论函数调用,后面也只以函数调用的角度来比较一下各个反射机制的性能。
在原生反射的框架下进行函数调用有两种较为常用的“招式”。分别如下:
1. 通过MethodInfo
以函数方法对象抽象调用函数,调用效率较低。
/// <summary> /// 原生反射测试 /// </summary> public class NativeReflectTest { /// <summary> /// 运行 /// </summary> public static void Run() { //类型对象 Type personType = typeof(Person); //方法信息 MethodInfo methodInfo = personType.GetMethod("Say"); //对象与参数 Person person = new Person(); String word = ""; Object[] param = new Object[] { word, 0 }; //极大次数调用测试运行时间 Profiler.Start(); for (int i = 0; i < 1000000; i++) { param[1] = i; methodInfo.Invoke(person, param); } Profiler.StopAndPrint("1000000 times invoked by Reflection: "); } }
2. 通过Assembly
用Assembly生成直接的对象,然后调用期则等同于直接调用函数。
/// <summary> /// 程序集测试 /// </summary> public class AssemblyTest { /// <summary> /// 运行 /// </summary> public static void Run() { Assembly assembly = Assembly.Load("FastMethodInvoker"); Person person = assembly.CreateInstance("FastMethodInvoker.example.subject.Person") as Person; String word = ""; Profiler.Start(); for (int i = 0; i < 1000000; ++i) { person.Say(ref word, i); } Profiler.StopAndPrint("1000000 times invoked by Assembly: "); } }
2.2. 委托(delegate)
其实代理本身与反射没有什么直接的关系,只是因为我们讨论的是函数调用,而委托天生就流着函数调用的血脉。相对于原生反射,委托显得更加特例化一些,他需要为每种不同的形式的函数预先定义出委托的类型,然后可以在不同的类的函数上进行绑定。委托比原生反射的抽象抽象程度弱化了一些。
绑定委托的“招式”如下:
public delegate void SayHandle(ref String word, int count); /// <summary> /// 代理测试 /// </summary> public class DelegateTest { /// <summary> /// 运行 /// </summary> public static void Run() { Type type = typeof(Person); MethodInfo methodInfo = type.GetMethod("Say"); Person person = new Person(); String word = ""; SayHandle delegateObject = Delegate.CreateDelegate(typeof(SayHandle), person, methodInfo) as SayHandle; Profiler.Start(); for (int i = 0; i < 1000000; i++) { delegateObject(ref word, i); } Profiler.StopAndPrint("1000000 times invoked by delegate: "); } }
2.3. 快速调用(fast invoke)
在codeproject上介绍了一种FastInvoke方法来进行函数反射。相对于原生反射,她提供了一种更底层的方式来实现。主要是MSIL语言来创建指令流,以达到调用期与平常代码相同的执行效率。
MSIL语言被称为Microsoft中间语言,主要用来做跨平台支持,C#将MSIL代码生成到当前机器的机器码。在FastInvoke中,直接生成调用函数的MSIL代码,则可以等同于编写C#直接调用函数的代码。
在小鱼酱包装后的接口中,FastInvoke方法的“招式”如下:
/// <summary> /// 快速调用测试 /// </summary> public class FastInvokeTest { /// <summary> /// 运行 /// </summary> public static void Run() { //快速调用句柄 FastInvokeHandler fastInvoker = FastInvoker.CreateHandler<Person>("Say"); //对象与参数 Person person = new Person(); String word = ""; Object[] param = new Object[] { word, 0 }; //极大次数调用测试运行时间 Profiler.Start(); for (int i = 0; i < 1000000; i++) { param[1] = i; fastInvoker(person, param); } Profiler.StopAndPrint("1000000 times invoked by FastInvoke: "); } }
这里是源代码地址:http://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker
这里是小鱼酱整理后的代码地址:http://pan.baidu.com/s/1hqAajuG
3. 性能比较
下面是几种反射调用的一个实验,分别调用一个简单函数极大次数(一百万次),如下:class Program { static void Main(string[] args) { //经典反射测试 NativeReflectTest.Run(); //快速调用测试 FastInvokeTest.Run(); //程序集 AssemblyTest.Run(); //代理 DelegateTest.Run(); //直接调用测试 DirectInvokeTest.Run(); Console.ReadLine(); } }
性能结果:
结论为,原生调用的时间消耗与直接调用相比较差别巨大;而Assembly需要先通过反射构建出对象,然后再通过直接调用的方式访问函数,构建对象的性能效率没有统计,如果加入统计过程中,Assembly方法的性能会比原生调用还要低,同时Assembly方法破坏了反射需要的统一抽象。delegate方法其实就是直接调用,但是与Assembly相同的是他同样也破坏了反射需要的统一抽象。而FastInvoke与直接调用性能相差不多,并且保持了统一形式进行访问的特性。
这里是性能比较的项目地址:http://pan.baidu.com/s/1hqAajuG
相关文章推荐
- C#抽象工厂模式的几种实现方法及比较
- 使用C#的反射机制时遇到的问题
- [zz]比较几种常用的中间件产品的通信机制(基于TCP/IP)
- c# 2种反射应用在AOP方法上的比较
- 使用C#的反射机制时遇到的问题
- C#抽象工厂模式的几种实现方法及比较
- C#抽象工厂模式的几种实现方法及比较【精】
- C#抽象工厂模式的几种实现方法及比较
- C#使用反射机制获取类信息
- C#抽象工厂模式的几种实现方法及比较
- 使用C#的反射机制时遇到的问题
- C#抽象工厂模式的几种实现方法及比较(转)
- C#使用反射机制获取类信息
- 如何理解C#中的反射机制
- 学习反射机制 c#
- 利用c#的反射机制得到类的信息
- C#使用反射机制获取类信息
- 使用C#的反射机制时遇到的问题
- C#抽象工厂模式的几种实现方法及比较(外摘)
- C#抽象工厂模式的几种实现方法及比较