zoukankan      html  css  js  c++  java
  • 改进的“以非泛型方式调用泛型方法”之基于DynamicMethod的实现

    本文针对双鱼座同志的以非泛型方式调用泛型方法一文,提出一种更通用的以非泛型方式调用泛型方法的实现——基于DynamicMethod的实现。
    基于DynamicMethod的实现的优点是,执行性能和双鱼座的文中实现的第5种方案——动态生成的非泛型接口包装相当(因为都是基于Emit的),但是,避免了原文实现中必须额外定义接口、Delegate的需要,从而,非常通用,应该是目前所能想到最佳实现。

    首先,贴出原文中的测试数据相对于DynamicMethod实现的比较和缺点:

    方案 耗时 比对 其他优点
    直接调用 18 1 不通用
    泛型委托包装 43 2.39 不通用
    反射 16538 918.78 通用,不需额外定义
    非泛型接口包装 60 3.33 通用,需要额外定义并实现
    动态生成的非泛型接口包装 72 4 通用,需要额外定义
    DynamicMethod实现 72 4 通用,无需额外定义

    实现代码如下:

      1    public abstract class DynamicMethodHelper
      2    {
      3        //该类不能实例化,只能静态调用
      4        private DynamicMethodHelper() {}
      5
      6        //通用的可变参数动态方法委托
      7        public delegate object DynamicMethodDelegate(params object[] paramObjs);
      8
      9        private static Dictionary<string, DynamicMethodDelegate> cache = new Dictionary<string, DynamicMethodDelegate>();
     10
     11        private static void LoadIndex(ILGenerator gen, int index)
     12        {
     13            switch (index)
     14            {
     15                case 0:
     16                    gen.Emit(OpCodes.Ldc_I4_0);
     17                    break;
     18                case 1:
     19                    gen.Emit(OpCodes.Ldc_I4_1);
     20                    break;
     21                case 2:
     22                    gen.Emit(OpCodes.Ldc_I4_2);
     23                    break;
     24                case 3:
     25                    gen.Emit(OpCodes.Ldc_I4_3);
     26                    break;
     27                case 4:
     28                    gen.Emit(OpCodes.Ldc_I4_4);
     29                    break;
     30                case 5:
     31                    gen.Emit(OpCodes.Ldc_I4_5);
     32                    break;
     33                case 6:
     34                    gen.Emit(OpCodes.Ldc_I4_6);
     35                    break;
     36                case 7:
     37                    gen.Emit(OpCodes.Ldc_I4_7);
     38                    break;
     39                case 8:
     40                    gen.Emit(OpCodes.Ldc_I4_8);
     41                    break;
     42                default:
     43                    if (index < 128)
     44                    {
     45                        gen.Emit(OpCodes.Ldc_I4_S, index);
     46                    }

     47                    else
     48                    {
     49                        gen.Emit(OpCodes.Ldc_I4, index);
     50                    }

     51                    break;
     52            }

     53        }

     54
     55        private static void StoreLocal(ILGenerator gen, int index)
     56        {
     57            switch (index)
     58            {
     59                case 0:
     60                    gen.Emit(OpCodes.Stloc_0);
     61                    break;
     62                case 1:
     63                    gen.Emit(OpCodes.Stloc_1);
     64                    break;
     65                case 2:
     66                    gen.Emit(OpCodes.Stloc_2);
     67                    break;
     68                case 3:
     69                    gen.Emit(OpCodes.Stloc_3);
     70                    break;
     71                default:
     72                    if (index < 128)
     73                    {
     74                        gen.Emit(OpCodes.Stloc_S, index);
     75                    }

     76                    else
     77                    {
     78                        gen.Emit(OpCodes.Stloc, index);
     79                    }

     80                    break;
     81            }

     82        }

     83
     84        private static void LoadLocal(ILGenerator gen, int index)
     85        {
     86            switch (index)
     87            {
     88                case 0:
     89                    gen.Emit(OpCodes.Ldloc_0);
     90                    break;
     91                case 1:
     92                    gen.Emit(OpCodes.Ldloc_1);
     93                    break;
     94                case 2:
     95                    gen.Emit(OpCodes.Ldloc_2);
     96                    break;
     97                case 3:
     98                    gen.Emit(OpCodes.Ldloc_3);
     99                    break;
    100                default:
    101                    if (index < 128)
    102                    {
    103                        gen.Emit(OpCodes.Ldloc_S, index);
    104                    }

    105                    else
    106                    {
    107                        gen.Emit(OpCodes.Ldloc, index);
    108                    }

    109                    break;
    110            }

    111        }

    112
    113        public static DynamicMethodDelegate GetDynamicMethodDelegate(MethodInfo genericMethodInfo, 
    114            params Type[] genericParameterTypes)
    115        {
    116            检查参数的有效性
    139
    140            构造用于缓存的key
    152
    153            DynamicMethodDelegate dmd;
    154
    155            lock (cache)
    156            {
    157                if (cache.ContainsKey(key))
    158                {
    159                    dmd = cache[key];
    160                }

    161                else
    162                {
    163                    //动态创建一个封装了泛型方法调用的非泛型方法,并返回绑定到他的DynamicMethodDelegate的实例
    164                    //返回的动态方法的实现在编译期就是以显式方法调用泛型方法的,因此,最大程度上避免了反射的性能损失
    165                    DynamicMethod dm = new DynamicMethod(Guid.NewGuid().ToString("N"), 
    166                        typeof(object), 
    167                        new Type[] typeof(object[]) }
    168                        typeof(string).Module);
    169
    170                    ILGenerator il = dm.GetILGenerator();
    171
    172                    创建所有方法的参数的本地变量
    193
    194                    从paramObjs参数中解析所有参数值到本地变量中
    213
    214                    执行目标方法
    235
    236                    il.Emit(OpCodes.Ret);
    237
    238                    dmd = (DynamicMethodDelegate)dm.CreateDelegate(typeof(DynamicMethodDelegate));
    239                    cache.Add(key, dmd);
    240                }

    241            }

    242
    243            return dmd;
    244        }

    245    }

    测试代码如下(基于在双鱼座原文的代码格式):

     1            List<int> list = new List<int>();
     2            System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch();
     3            watch.Reset();
     4            watch.Start();
     5            for (int i = 0; i < REPEAT_TIME; i++)
     6            {
     7                Program.Add<int>(i, list);
     8            }

     9            watch.Stop();
    10            long l1 = watch.ElapsedMilliseconds;
    11            watch.Reset();
    12            MethodInfo mi = typeof(Program).GetMethod("Add");
    13            DynamicMethodHelper.DynamicMethodDelegate dmd = DynamicMethodHelper.GetDynamicMethodDelegate(mi, typeof(int));
    14            watch.Start();
    15            for (int i = 0; i < REPEAT_TIME; i++)
    16            {
    17                dmd(i, list);
    18            }

    19            watch.Stop();
    20            long l2 = watch.ElapsedMilliseconds;
    21            Console.WriteLine("{0}\n{1} vs {2}", list.Count, l1, l2);
    22            Console.ReadLine();


    下载测试源代码

  • 相关阅读:
    OSPF
    【今日CS 视觉论文速览】 24 Jan 2019
    【今日CS 视觉论文速览】Wed, 23 Jan 2019
    【今日CS 视觉论文速览】 21 Jan 2019
    【Processing学习笔记】安装与入门
    【今日CS 视觉论文速览】Part2, 18 Jan 2019
    【今日CS 视觉论文速览】Fri, 18 Jan 2019
    【今日CS 视觉论文速览】Thu, 17 Jan 2019
    【今日CS 视觉论文速览】Part2, 16 Jan 2019
    【今日CS 视觉论文速览】Wed, 16 Jan 2019
  • 原文地址:https://www.cnblogs.com/teddyma/p/684306.html
Copyright © 2011-2022 走看看