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



5

6

7

8

9

10

11

12



13

14



15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44



45

46

47

48



49

50

51

52

53

54

55

56



57

58



59

60

61

62

63

64

65

66

67

68

69

70

71

72

73



74

75

76

77



78

79

80

81

82

83

84

85



86

87



88

89

90

91

92

93

94

95

96

97

98

99

100

101

102



103

104

105

106



107

108

109

110

111

112

113

114

115



116


117

118

119



120

121

122

123

124



125

126



127

128

129

130

131



132

133



134

135

136

137

138

139

140


141

142

143

144



145

146



147

148

149

150

151

152

153

154

155

156



157

158



159

160

161

162



163

164

165

166

167



168

169

170

171

172


173

174

175

176

177



178

179

180

181



182

183

184

185

186

187

188



189

190

191

192

193

194


195

196

197



198

199

200

201

202



203

204

205

206



207

208

209

210

211

212

213

214


215

216

217



218

219

220

221



222

223

224

225



226

227

228

229

230



231

232

233

234

235

236

237

238

239

240

241

242

243

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

3

4

5

6



7

8

9

10

11

12

13

14

15

16



17

18

19

20

21

22

下载测试源代码