基于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
}

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

139

140

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

193

194

213

214

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

下载测试源代码