改进的“以非泛型方式调用泛型方法”之基于DynamicMethod的实现

本文介绍了一种改进的非泛型调用泛型方法的技术,通过使用DynamicMethod来提高性能并减少代码复杂性。该方法避免了定义额外接口和委托的需求,实现了更通用且高效的解决方案。

改进的“以非泛型方式调用泛型方法”之基于DynamicMethod的实现

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

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

方案耗时比对其他优点
直接调用181不通用
泛型委托包装432.39不通用
反射16538918.78通用,不需额外定义
非泛型接口包装603.33通用,需要额外定义并实现
动态生成的非泛型接口包装724通用,需要额外定义
DynamicMethod实现724通用,无需额外定义

实现代码如下:

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

 47InBlock.gif                    else
 48ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
 49InBlock.gif                        gen.Emit(OpCodes.Ldc_I4, index);
 50ExpandedSubBlockEnd.gif                    }

 51InBlock.gif                    break;
 52ExpandedSubBlockEnd.gif            }

 53ExpandedSubBlockEnd.gif        }

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

 76InBlock.gif                    else
 77ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
 78InBlock.gif                        gen.Emit(OpCodes.Stloc, index);
 79ExpandedSubBlockEnd.gif                    }

 80InBlock.gif                    break;
 81ExpandedSubBlockEnd.gif            }

 82ExpandedSubBlockEnd.gif        }

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

105InBlock.gif                    else
106ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
107InBlock.gif                        gen.Emit(OpCodes.Ldloc, index);
108ExpandedSubBlockEnd.gif                    }

109InBlock.gif                    break;
110ExpandedSubBlockEnd.gif            }

111ExpandedSubBlockEnd.gif        }

112InBlock.gif
113InBlock.gif        public static DynamicMethodDelegate GetDynamicMethodDelegate(MethodInfo genericMethodInfo, 
114InBlock.gif            params Type[] genericParameterTypes)
115ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
116ContractedSubBlock.gifExpandedSubBlockStart.gif            检查参数的有效性#region 检查参数的有效性
117InBlock.gif
118InBlock.gif            if (genericMethodInfo == null)
119ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
120InBlock.gif                throw new ArgumentNullException("需要被调用的方法的genericMethodInfo不能为空!");
121ExpandedSubBlockEnd.gif            }

122InBlock.gif
123InBlock.gif            if (genericParameterTypes != null)
124ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
125InBlock.gif                if (genericParameterTypes.Length != genericMethodInfo.GetGenericArguments().Length)
126ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
127InBlock.gif                    throw new ArgumentException("genericMethodInfo和泛型参数类型的数量不一致!");
128ExpandedSubBlockEnd.gif                }

129ExpandedSubBlockEnd.gif            }

130InBlock.gif            else
131ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
132InBlock.gif                if (genericMethodInfo.GetGenericArguments().Length > 0)
133ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
134InBlock.gif                    throw new ArgumentException("没有为genericMethodInfo指定泛型参数类型!");
135ExpandedSubBlockEnd.gif                }

136ExpandedSubBlockEnd.gif            }

137InBlock.gif
138ExpandedSubBlockEnd.gif            #endregion

139InBlock.gif
140ContractedSubBlock.gifExpandedSubBlockStart.gif            构造用于缓存的key#region  构造用于缓存的key
141InBlock.gif
142InBlock.gif            string key = genericMethodInfo.DeclaringType.ToString() + "|" + genericMethodInfo.ToString();
143InBlock.gif            if (genericParameterTypes != null)
144ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
145InBlock.gif                for (int i = 0; i < genericParameterTypes.Length; ++i)
146ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
147InBlock.gif                    key += "|" + genericParameterTypes[i].ToString();
148ExpandedSubBlockEnd.gif                }

149ExpandedSubBlockEnd.gif            }

150InBlock.gif
151ExpandedSubBlockEnd.gif            #endregion

152InBlock.gif
153InBlock.gif            DynamicMethodDelegate dmd;
154InBlock.gif
155InBlock.gif            lock (cache)
156ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
157InBlock.gif                if (cache.ContainsKey(key))
158ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
159InBlock.gif                    dmd = cache[key];
160ExpandedSubBlockEnd.gif                }

161InBlock.gif                else
162ExpandedSubBlockStart.gifContractedSubBlock.gif                dot.gif{
163InBlock.gif                    //动态创建一个封装了泛型方法调用的非泛型方法,并返回绑定到他的DynamicMethodDelegate的实例
164InBlock.gif                    //返回的动态方法的实现在编译期就是以显式方法调用泛型方法的,因此,最大程度上避免了反射的性能损失
165InBlock.gif                    DynamicMethod dm = new DynamicMethod(Guid.NewGuid().ToString("N"), 
166InBlock.gif                        typeof(object), 
167ExpandedSubBlockStart.gifContractedSubBlock.gif                        new Type[] dot.giftypeof(object[]) }
168InBlock.gif                        typeof(string).Module);
169InBlock.gif
170InBlock.gif                    ILGenerator il = dm.GetILGenerator();
171InBlock.gif
172ContractedSubBlock.gifExpandedSubBlockStart.gif                    创建所有方法的参数的本地变量#region 创建所有方法的参数的本地变量
173InBlock.gif
174InBlock.gif                    //首先获得目标方法的MethodInfo
175InBlock.gif                    MethodInfo makeGenericMethodInfo;
176InBlock.gif                    if (genericParameterTypes != null && genericParameterTypes.Length > 0)
177ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
178InBlock.gif                        makeGenericMethodInfo = genericMethodInfo.MakeGenericMethod(genericParameterTypes);
179ExpandedSubBlockEnd.gif                    }

180InBlock.gif                    else
181ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
182InBlock.gif                        makeGenericMethodInfo = genericMethodInfo;
183ExpandedSubBlockEnd.gif                    }

184InBlock.gif
185InBlock.gif                    //声明本地变量
186InBlock.gif                    ParameterInfo[] pis = makeGenericMethodInfo.GetParameters();
187InBlock.gif                    for (int i = 0; i < pis.Length; ++i)
188ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
189InBlock.gif                        il.DeclareLocal(pis[i].ParameterType);
190ExpandedSubBlockEnd.gif                    }

191InBlock.gif
192ExpandedSubBlockEnd.gif                    #endregion

193InBlock.gif
194ContractedSubBlock.gifExpandedSubBlockStart.gif                    从paramObjs参数中解析所有参数值到本地变量中#region 从paramObjs参数中解析所有参数值到本地变量中
195InBlock.gif
196InBlock.gif                    for (int i = 0; i < pis.Length; ++i)
197ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
198InBlock.gif                        il.Emit(OpCodes.Ldarg_0);
199InBlock.gif                        LoadIndex(il, i);
200InBlock.gif                        il.Emit(OpCodes.Ldelem_Ref);
201InBlock.gif                        if (pis[i].ParameterType.IsValueType)
202ExpandedSubBlockStart.gifContractedSubBlock.gif                        dot.gif{
203InBlock.gif                            il.Emit(OpCodes.Unbox_Any, pis[i].ParameterType);
204ExpandedSubBlockEnd.gif                        }

205InBlock.gif                        else if (pis[i].ParameterType != typeof(object))
206ExpandedSubBlockStart.gifContractedSubBlock.gif                        dot.gif{
207InBlock.gif                            il.Emit(OpCodes.Castclass, pis[i].ParameterType);
208ExpandedSubBlockEnd.gif                        }

209InBlock.gif                        StoreLocal(il, i);
210ExpandedSubBlockEnd.gif                    }

211InBlock.gif
212ExpandedSubBlockEnd.gif                    #endregion

213InBlock.gif
214ContractedSubBlock.gifExpandedSubBlockStart.gif                    执行目标方法#region 执行目标方法
215InBlock.gif
216InBlock.gif                    for (int i = 0; i < pis.Length; ++i)
217ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
218InBlock.gif                        LoadLocal(il, i);
219ExpandedSubBlockEnd.gif                    }

220InBlock.gif                    if (makeGenericMethodInfo.IsStatic)
221ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
222InBlock.gif                        il.Emit(OpCodes.Call, makeGenericMethodInfo);
223ExpandedSubBlockEnd.gif                    }

224InBlock.gif                    else
225ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
226InBlock.gif                        throw new NotImplementedException("暂时还没有实现该功能!");
227ExpandedSubBlockEnd.gif                    }

228InBlock.gif
229InBlock.gif                    if (makeGenericMethodInfo.ReturnType == typeof(void))
230ExpandedSubBlockStart.gifContractedSubBlock.gif                    dot.gif{
231InBlock.gif                        il.Emit(OpCodes.Ldnull);
232ExpandedSubBlockEnd.gif                    }

233InBlock.gif
234ExpandedSubBlockEnd.gif                    #endregion

235InBlock.gif
236InBlock.gif                    il.Emit(OpCodes.Ret);
237InBlock.gif
238InBlock.gif                    dmd = (DynamicMethodDelegate)dm.CreateDelegate(typeof(DynamicMethodDelegate));
239InBlock.gif                    cache.Add(key, dmd);
240ExpandedSubBlockEnd.gif                }

241ExpandedSubBlockEnd.gif            }

242InBlock.gif
243InBlock.gif            return dmd;
244ExpandedSubBlockEnd.gif        }

245ExpandedBlockEnd.gif    }

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

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

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

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


下载测试源代码

转载于:https://www.cnblogs.com/erichzhou/archive/2007/03/29/693133.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值