反射VS委托,到底谁更快?

       有时候我们需要动态调用一个方法,到底用什么方法呢?很多人想到了反射,有的人也想到了委托。大家都知道反射很慢,因为反射的类型不安全和以寻找字符串的方式来匹配相对应的成员,所以也有的人用委托,那到底谁更快呢?来看一个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次,它需要的时间如下:

呵呵,心血来潮,跟大家分享一下,太忙了,可能写的不好,大家见谅了。

posted @   静女  阅读(1134)  评论(4编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示