有时候我们需要动态调用一个方法,到底用什么方法呢?很多人想到了反射,有的人也想到了委托。大家都知道反射很慢,因为反射的类型不安全和以寻找字符串的方式来匹配相对应的成员,所以也有的人用委托,那到底谁更快呢?来看一个demo:
1 public interface IGetData 2 { 3 int GetData(int data); 4 } 5 6 public class Test : IGetData 7 { 8 public int GetData(int data) 9 {10 return data;11 }12 }
假设正常情况下无法访问Test中的方法
public class InvokeTestMember { private const BindingFlags flag = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public; /// <summary> /// 使用反射 /// </summary> public void InvokeByReflect() { Test obj = (Test)Activator.CreateInstance(typeof(Test)); MethodInfo mi = typeof(Test).GetMethod("GetData", flag); object result = mi.Invoke(obj, new object[] { 10 }); } /// <summary> /// 使用委托 /// </summary> public void InvokeByCreateDelegate() { Test obj = (Test)Activator.CreateInstance(typeof(Test)); MethodInfo mi = typeof(Test).GetMethod("GetData", flag); Func<int, int> del = (Func<int, int>)Delegate.CreateDelegate(typeof(Func<int, int>), obj, mi); object result = del(10); } }
现在来测试一下谁更快:
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 Go(); 6 } 7 8 static void Go() 9 {10 InvokeTestMember itm = new InvokeTestMember();11 12 Stopwatch sw = Stopwatch.StartNew();13 for (int i = 0; i < 1000 * 1000; i++)14 {15 itm.InvokeByCreateDelegate();16 }17 Console.WriteLine("invokebydelegate: " + sw.Elapsed);18 19 sw = Stopwatch.StartNew();20 for (int i = 0; i < 1000 * 1000; i++)21 {22 itm.InvokeByReflect();23 }24 Console.WriteLine("invokebyreflect: " + sw.Elapsed);25 }26 }
下面是输出结果:
有点意外啊,反射更快,至于是什么原因,大家去讨论一下吧,我现在也不是很清楚,有点复杂啊。。。。。。
当然了,还有更好的方法,速度更快,就是使用Dynamic关键字,此关键字在运行时跟object有点类似,它创建的对象只能在运行时去匹配相关的类型成员,所以有点类型不安全哦,下面是用dynamic关键字调用的方法,很简单:
public void InvokeByDynamicKeyword() { dynamic obj = (Test)Activator.CreateInstance(typeof(Test)); object result = obj.GetData(10); }
同样执行1000*1000次,它需要的时间如下:
当然了,我前面用到了接口,对于反射速度慢的最佳解决方案是,实现一个接口或一个抽象类,用他们的引用指向实现该接口的成员实例或继承该抽象类的成员实例,这是典型的插件编程模式,来看一下代码,很简单:
public void InvokeByInterface() { IGetData obj = (IGetData)Activator.CreateInstance(typeof(Test)); object result = obj.GetData(10); }
同样执行1000*1000次,它需要的时间如下:
联系客服