下载源码:NBear.Common.zip
介绍
CodeGenerator
该类很多地方参照了.NET 3.0的System.Runtime.Serialization.dll中的同名internal类,他封装了Emit中的各种Emit层面的常用操作逻辑,包括Ld各种value、成员变量,if-else,case switch,loop等分支控制等,扩展的版本使用DesignByContract对所有的输入参数进行了检查,并扩展了对Emit Constructor,Method,get、set Method of Property的支持。
关于Emit DynamicMethod的示例,大家可以参见稍后介绍的DynamicMethodFactory类,这里先给出一个使用该类Emit一个类,并实现一个接口的示例代码,该示例代码为包含于源码的CodeGenerator.cs文件末尾的UnitTest代码:
1
namespace CodeGeneratorUnitTest
2
{
3
public interface ITest
4
{
5
string Wow(string str);
6
}
7
8
public class UnitTest
9
{
10
public static void TestEmitInterface()
11
{
12
AssemblyName assName = new AssemblyName("TestEmitInterface");
13
AssemblyBuilder assBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assName, AssemblyBuilderAccess.Run);
14
ModuleBuilder modBuilder = assBuilder.DefineDynamicModule(assBuilder.GetName().Name);
15
TypeBuilder typeBuilder = modBuilder.DefineType("TestEmitInterface.TestImpl", TypeAttributes.Public);
16
typeBuilder.AddInterfaceImplementation(typeof(ITest));
17
18
CodeGenerator ctor = new CodeGenerator(typeBuilder, "ctor", MethodAttributes.Public, CallingConventions.Standard, null, Type.EmptyTypes);
19
ctor.Ldarg(0);
20
ctor.Call(typeof(object).GetConstructor(Type.EmptyTypes));
21
ctor.Ret();
22
23
MethodInfo mi = typeof(ITest).GetMethod("Wow");
24
25
CodeGenerator wow = new CodeGenerator(typeBuilder, mi.Name, mi.Attributes & (~MethodAttributes.Abstract) | MethodAttributes.Public, mi.CallingConvention, mi.ReturnType, new Type[] { typeof(string) });
26
wow.Ldarg(1);
27
wow.Ret();
28
29
typeBuilder.DefineMethodOverride(wow.CurrentMethod, mi);
30
31
Type testImplType = typeBuilder.CreateType();
32
ITest test = (ITest)Activator.CreateInstance(testImplType);
33
Check.Assert(test.Wow("hello") == "hello");
34
}
35
}
36
}

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

以上代码Emit了一个TestImpl类,它实现了ITest接口,包含一个默认构造函数和一个Wow方法,注意,构造函数和方法都是通过CodeGenerator Emit的,这里的逻辑比较简单,但应该已经能看到相对于ilGen.Emit(OpCodes.XXX, YYY)这样的语法的简化,如果实现逻辑复杂,对整个Emit过程的简化就更明显。
DynamicMethodFactory
该类的主要功能包括:实例化第三方程序集中的internal类型(DynamicMethodFactory.CreateInstance()方法),为指定类型(可以是第三方程序集中的internal类型)的泛型或非泛型方法、属性、字段的读写生成非强类型的Delegate(通过DynamicMethod实现,不使用反射,性能接近直接访问)。
下面先给出一个该类中为一个Method创建一个DynamicMethod,并返回其Delegate的示例,DynamicMethod是使用前面介绍的CodeGenerator实现的:
1
protected static DynamicMethodProxyHandler DoGetMethodDelegate(
2
Module targetModule,
3
MethodInfo genericMethodInfo,
4
params Type[] genericParameterTypes)
5
{
6
Check preconditions
16
17
//Create a dynamic method proxy delegate used to call the specified methodinfo
18
CodeGenerator gen = new CodeGenerator(targetModule);
19
gen.BeginMethod("dm" + Guid.NewGuid().ToString("N"), typeof(DynamicMethodProxyHandler));
20
MethodInfo makeGenericMethodInfo = MakeMethodGeneric(genericMethodInfo, genericParameterTypes);
21
gen.Ldarg(0);
22
LoadParameters(gen, makeGenericMethodInfo.GetParameters(), false);
23
gen.Call(makeGenericMethodInfo);
24
CastValueToObject(gen, makeGenericMethodInfo.ReturnType);
25
26
return (DynamicMethodProxyHandler)gen.EndMethod();
27
}

2

3

4

5

6

16

17

18

19

20

21

22

23

24

25

26

27


代码是不是相对比较简单呢(当然是相对于自己写所有的Emit来讲的),注意这里的LoadParameter方法的实现您可以发现,为方法生成调用Delegate是完美支持输入输出参数的。
下面给出DynamicMethodFactory类的UnitTest代码,演示了对方法、字段和属性的生成Delegate和基于Delegate的读写,且包括对输入输出参数的使用:
1
namespace DynamicMethodFactoryUnitTest
2
{
3
public class TestClass
4
{
5
public static void StaticReturnVoidMethod()
6
{
7
}
8
9
public static int StaticReturnIntMethod(string str, int i, ref int refInt, ref string refStr)
10
{
11
Check.Assert(str == "str");
12
Check.Assert(i == 1);
13
Check.Assert(refInt == 3);
14
Check.Assert(refStr == "instr");
15
16
int ret = i + refInt;
17
refInt = i + 1;
18
refStr = "ref" + str;
19
20
Check.Assert(refInt == 2);
21
Check.Assert(ret == 4);
22
Check.Assert(refStr == "refstr");
23
24
return ret;
25
}
26
27
public static int StaticIntField;
28
29
public static int StaticIntProperty
30
{
31
get
32
{
33
return StaticIntField;
34
}
35
set
36
{
37
StaticIntField = value;
38
}
39
}
40
41
public void NonStaticReturnVoidMethod()
42
{
43
}
44
45
public int NonStaticReturnIntMethod(string str, int i, out int outInt, out string outStr)
46
{
47
outInt = i + 1;
48
Check.Assert(outInt == 2);
49
outStr = "out" + str;
50
Check.Assert(outStr == "outstr");
51
return i + 2;
52
}
53
54
public int NonStaticIntField;
55
56
public int NonStaticIntProperty
57
{
58
get
59
{
60
return NonStaticIntField;
61
}
62
set
63
{
64
NonStaticIntField = value;
65
}
66
}
67
}
68
69
public class UnitTest
70
{
71
private static DynamicMethodFactory fac = new DynamicMethodFactory();
72
73
public static void TestStaticMethod()
74
{
75
StaticDynamicMethodProxyHandler handler = fac.GetStaticMethodDelegate(typeof(TestClass).GetMethod("StaticReturnVoidMethod"));
76
handler(null);
77
78
object[] inputParams = new object[] { "str", 1, 3, "instr" };
79
handler = fac.GetStaticMethodDelegate(typeof(TestClass).GetMethod("StaticReturnIntMethod"));
80
object ret = handler(inputParams);
81
Check.Assert(((int)inputParams[2]) == 2);
82
Check.Assert(((string)inputParams[3]) == "refstr");
83
Check.Assert(((int)ret) == 4);
84
}
85
86
public static void TestStaticField()
87
{
88
TestClass.StaticIntField = -1;
89
FieldInfo field = typeof(TestClass).GetField("StaticIntField"); ;
90
StaticDynamicMethodProxyHandler handler = fac.GetStaticFieldSetDelegate(field);
91
handler(new object[] { 5 });
92
Check.Assert(TestClass.StaticIntField == 5);
93
handler = fac.GetStaticFieldGetDelegate(field);
94
Check.Assert(((int)handler(null)) == 5);
95
}
96
97
public static void TestStaticProperty()
98
{
99
TestClass.StaticIntField = -1;
100
PropertyInfo property = typeof(TestClass).GetProperty("StaticIntProperty"); ;
101
StaticDynamicMethodProxyHandler handler = fac.GetStaticMethodDelegate(property.GetSetMethod());
102
handler(new object[] { 5 });
103
Check.Assert(TestClass.StaticIntProperty == 5);
104
handler = fac.GetStaticMethodDelegate(property.GetGetMethod());
105
Check.Assert(((int)handler(null)) == 5);
106
}
107
108
public static void TestNonStaticMethod()
109
{
110
TestClass obj = new TestClass();
111
112
DynamicMethodProxyHandler handler = fac.GetMethodDelegate(typeof(TestClass).GetMethod("NonStaticReturnVoidMethod"));
113
handler(obj, null);
114
115
object[] inputParams = new object[] { "str", 1, null, null };
116
handler = fac.GetMethodDelegate(typeof(TestClass).GetMethod("NonStaticReturnIntMethod"));
117
object ret = handler(obj, inputParams);
118
Check.Assert(((int)inputParams[2]) == 2);
119
Check.Assert(((string)inputParams[3]) == "outstr");
120
Check.Assert(((int)ret) == 3);
121
}
122
123
public static void TestNonStaticField()
124
{
125
TestClass obj = new TestClass();
126
obj.NonStaticIntField = -1;
127
128
FieldInfo field = typeof(TestClass).GetField("NonStaticIntField"); ;
129
DynamicMethodProxyHandler handler = fac.GetFieldSetDelegate(field);
130
handler(obj, new object[] { 5 });
131
Check.Assert(obj.NonStaticIntField == 5);
132
handler = fac.GetFieldGetDelegate(field);
133
Check.Assert(((int)handler(obj, null)) == 5);
134
}
135
136
public static void TestNonStaticProperty()
137
{
138
TestClass obj = new TestClass();
139
obj.NonStaticIntField = -1;
140
141
PropertyInfo property = typeof(TestClass).GetProperty("NonStaticIntProperty"); ;
142
DynamicMethodProxyHandler handler = fac.GetMethodDelegate(property.GetSetMethod());
143
handler(obj, new object[] { 5 });
144
Check.Assert(obj.NonStaticIntField == 5);
145
handler = fac.GetMethodDelegate(property.GetGetMethod());
146
Check.Assert(((int)handler(obj, null)) == 5);
147
}
148
}
149
}

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

DynamicMethodFactory类还可以用于以非泛型方法的调用语法调用泛型方法,在之前的一篇文章介绍过,这里就不重复了,感兴趣的朋友可以参见:改进的以非泛型方式调用泛型方法”之基于DynamicMethod的实现。
有任何问题欢迎回复讨论。
//The End