改进的“以非泛型方式调用泛型方法”之基于DynamicMethod的实现
来源:互联网 发布:url加端口号 编辑:程序博客网 时间:2024/05/10 14:03
本文针对双鱼座同志的以非泛型方式调用泛型方法一文,提出一种更通用的以非泛型方式调用泛型方法的实现——基于DynamicMethod的实现。
基于DynamicMethod的实现的优点是,执行性能和双鱼座的文中实现的第5种方案——动态生成的非泛型接口包装相当(因为都是基于Emit的),但是,避免了原文实现中必须额外定义接口、Delegate的需要,从而,非常通用,应该是目前所能想到最佳实现。
首先,贴出原文中的测试数据相对于DynamicMethod实现的比较和缺点:
方案 耗时 比对 其他优点 直接调用 18 1 不通用 泛型委托包装 43 2.39 不通用 反射 16538 918.78 通用,不需额外定义 非泛型接口包装 60 3.33 通用,需要额外定义并实现 动态生成的非泛型接口包装 72 4 通用,需要额外定义 DynamicMethod实现 72 4 通用,无需额外定义
实现代码如下:
测试代码如下(基于在双鱼座原文的代码格式):
下载测试源代码
基于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 检查参数的有效性#region 检查参数的有效性
117
118 if (genericMethodInfo == null)
119 {
120 throw new ArgumentNullException("需要被调用的方法的genericMethodInfo不能为空!");
121 }
122
123 if (genericParameterTypes != null)
124 {
125 if (genericParameterTypes.Length != genericMethodInfo.GetGenericArguments().Length)
126 {
127 throw new ArgumentException("genericMethodInfo和泛型参数类型的数量不一致!");
128 }
129 }
130 else
131 {
132 if (genericMethodInfo.GetGenericArguments().Length > 0)
133 {
134 throw new ArgumentException("没有为genericMethodInfo指定泛型参数类型!");
135 }
136 }
137
138 #endregion
139
140 构造用于缓存的key#region 构造用于缓存的key
141
142 string key = genericMethodInfo.DeclaringType.ToString() + "|" + genericMethodInfo.ToString();
143 if (genericParameterTypes != null)
144 {
145 for (int i = 0; i < genericParameterTypes.Length; ++i)
146 {
147 key += "|" + genericParameterTypes[i].ToString();
148 }
149 }
150
151 #endregion
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 创建所有方法的参数的本地变量#region 创建所有方法的参数的本地变量
173
174 //首先获得目标方法的MethodInfo
175 MethodInfo makeGenericMethodInfo;
176 if (genericParameterTypes != null && genericParameterTypes.Length > 0)
177 {
178 makeGenericMethodInfo = genericMethodInfo.MakeGenericMethod(genericParameterTypes);
179 }
180 else
181 {
182 makeGenericMethodInfo = genericMethodInfo;
183 }
184
185 //声明本地变量
186 ParameterInfo[] pis = makeGenericMethodInfo.GetParameters();
187 for (int i = 0; i < pis.Length; ++i)
188 {
189 il.DeclareLocal(pis[i].ParameterType);
190 }
191
192 #endregion
193
194 从paramObjs参数中解析所有参数值到本地变量中#region 从paramObjs参数中解析所有参数值到本地变量中
195
196 for (int i = 0; i < pis.Length; ++i)
197 {
198 il.Emit(OpCodes.Ldarg_0);
199 LoadIndex(il, i);
200 il.Emit(OpCodes.Ldelem_Ref);
201 if (pis[i].ParameterType.IsValueType)
202 {
203 il.Emit(OpCodes.Unbox_Any, pis[i].ParameterType);
204 }
205 else if (pis[i].ParameterType != typeof(object))
206 {
207 il.Emit(OpCodes.Castclass, pis[i].ParameterType);
208 }
209 StoreLocal(il, i);
210 }
211
212 #endregion
213
214 执行目标方法#region 执行目标方法
215
216 for (int i = 0; i < pis.Length; ++i)
217 {
218 LoadLocal(il, i);
219 }
220 if (makeGenericMethodInfo.IsStatic)
221 {
222 il.Emit(OpCodes.Call, makeGenericMethodInfo);
223 }
224 else
225 {
226 throw new NotImplementedException("暂时还没有实现该功能!");
227 }
228
229 if (makeGenericMethodInfo.ReturnType == typeof(void))
230 {
231 il.Emit(OpCodes.Ldnull);
232 }
233
234 #endregion
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 }
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 检查参数的有效性#region 检查参数的有效性
117
118 if (genericMethodInfo == null)
119 {
120 throw new ArgumentNullException("需要被调用的方法的genericMethodInfo不能为空!");
121 }
122
123 if (genericParameterTypes != null)
124 {
125 if (genericParameterTypes.Length != genericMethodInfo.GetGenericArguments().Length)
126 {
127 throw new ArgumentException("genericMethodInfo和泛型参数类型的数量不一致!");
128 }
129 }
130 else
131 {
132 if (genericMethodInfo.GetGenericArguments().Length > 0)
133 {
134 throw new ArgumentException("没有为genericMethodInfo指定泛型参数类型!");
135 }
136 }
137
138 #endregion
139
140 构造用于缓存的key#region 构造用于缓存的key
141
142 string key = genericMethodInfo.DeclaringType.ToString() + "|" + genericMethodInfo.ToString();
143 if (genericParameterTypes != null)
144 {
145 for (int i = 0; i < genericParameterTypes.Length; ++i)
146 {
147 key += "|" + genericParameterTypes[i].ToString();
148 }
149 }
150
151 #endregion
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 创建所有方法的参数的本地变量#region 创建所有方法的参数的本地变量
173
174 //首先获得目标方法的MethodInfo
175 MethodInfo makeGenericMethodInfo;
176 if (genericParameterTypes != null && genericParameterTypes.Length > 0)
177 {
178 makeGenericMethodInfo = genericMethodInfo.MakeGenericMethod(genericParameterTypes);
179 }
180 else
181 {
182 makeGenericMethodInfo = genericMethodInfo;
183 }
184
185 //声明本地变量
186 ParameterInfo[] pis = makeGenericMethodInfo.GetParameters();
187 for (int i = 0; i < pis.Length; ++i)
188 {
189 il.DeclareLocal(pis[i].ParameterType);
190 }
191
192 #endregion
193
194 从paramObjs参数中解析所有参数值到本地变量中#region 从paramObjs参数中解析所有参数值到本地变量中
195
196 for (int i = 0; i < pis.Length; ++i)
197 {
198 il.Emit(OpCodes.Ldarg_0);
199 LoadIndex(il, i);
200 il.Emit(OpCodes.Ldelem_Ref);
201 if (pis[i].ParameterType.IsValueType)
202 {
203 il.Emit(OpCodes.Unbox_Any, pis[i].ParameterType);
204 }
205 else if (pis[i].ParameterType != typeof(object))
206 {
207 il.Emit(OpCodes.Castclass, pis[i].ParameterType);
208 }
209 StoreLocal(il, i);
210 }
211
212 #endregion
213
214 执行目标方法#region 执行目标方法
215
216 for (int i = 0; i < pis.Length; ++i)
217 {
218 LoadLocal(il, i);
219 }
220 if (makeGenericMethodInfo.IsStatic)
221 {
222 il.Emit(OpCodes.Call, makeGenericMethodInfo);
223 }
224 else
225 {
226 throw new NotImplementedException("暂时还没有实现该功能!");
227 }
228
229 if (makeGenericMethodInfo.ReturnType == typeof(void))
230 {
231 il.Emit(OpCodes.Ldnull);
232 }
233
234 #endregion
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();
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();
下载测试源代码
- 改进的“以非泛型方式调用泛型方法”之基于DynamicMethod的实现
- 以非泛型方式调用泛型方法
- 以非泛型方式调用泛型方法
- 以非泛型方式调用泛型方法
- 使用.net 中的动态方法编程备忘录3(DynamicMethod 的最优访问方式)
- 基于单片机的多级菜单实现方法改进
- 基于Qt有限状态机人工智能的一种实现及改进方法
- NISLVMP:一种新的保护方式,基于VM,改进之<译>
- 基于WebService实现远程调用方式的系统间通信
- 基于WebService实现远程调用方式的系统间通信
- 将wcf 以webservice的方式调用
- 复习struts2之基于XML配置方式实现对action的所有方法进行校验
- 基于一种改进的提取形状特征向量方法,实现图像检索
- C#错误:不能以方法的方式使用不可调用的
- activity以绑定服务的方式开启服务并调用服务里面的方法
- 以 Swift 的方式思考,第二部分:调用数组的 Map 方法
- 用栈的方式实现递归调用(以n的阶乘为例)
- RxBus进阶------基于RxJava2.x实现以注解的方式传递消息
- 报数游戏
- 基于NBear的快速开发解决方案
- NbearV3.7新增强类型查询功能演示教程
- 安装 system management server 详细步骤
- 源码发布 - DynamicMethodProxyFactory组件
- 改进的“以非泛型方式调用泛型方法”之基于DynamicMethod的实现
- 实现NBearDataSource控件 - 02-11 20:30 修订 - 新增Master/Detail实体CRUD示例
- ADO.NET、NBear和NHibernate简单读写性能比较
- MSSQL生成日期列表
- Suggested NBear Framework Based FDD Development Steps
- NBearV3教程——MVP(Model/View/Presenter)篇
- NBearV3.3.7 发布 - 震撼人心的VsPlugin来了!
- NBearV3——VsPlugin使用教程
- NBearV3教程——Cache篇