本文介绍一组NBearV4中的基于Emit动态生成代码的辅助类,部分概念在本人的blog之前的文章中或多或少都有介绍,这里包含最新的更新及演示、测试。主要是两个类:CodeGenerator和
DynamicMethodFactory。前者提供了一种经过封装的,简化Emit方法(包括Emit DynamicMethod,Constructor,Method,get、set Method of Property)的方案;后者基于前者,实现了一种访问指定类(可以是第三方程序集的internal类)的方法或成员变量,实例化第三方程序集中的internal类型,高性能的以非泛型语法访问泛型方法的机制(通过DynamicMethod和Delegate实现)。
下载源码: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代码:
以上代码Emit了一个TestImpl类,它实现了ITest接口,包含一个默认构造函数和一个Wow方法,注意,构造函数和方法都是通过CodeGenerator Emit的,这里的逻辑比较简单,但应该已经能看到相对于ilGen.Emit(OpCodes.XXX, YYY)这样的语法的简化,如果实现逻辑复杂,对整个Emit过程的简化就更明显。
DynamicMethodFactory
该类的主要功能包括:实例化第三方程序集中的internal类型(DynamicMethodFactory.CreateInstance()方法),为指定类型(可以是第三方程序集中的internal类型)的泛型或非泛型方法、属性、字段的读写生成非强类型的Delegate(通过DynamicMethod实现,不使用反射,性能接近直接访问)。
下面先给出一个该类中为一个Method创建一个DynamicMethod,并返回其Delegate的示例,DynamicMethod是使用前面介绍的CodeGenerator实现的:
LoadParameters和CastValueToObject的代码
1
private static void LoadParameters(CodeGenerator gen, ParameterInfo[] pis, bool isMethodStatic)
2
{
3
Check.Require(gen, "gen");
4
5
if (pis != null)
6
{
7
for (int i = 0; i < pis.Length; ++i)
8
{
9
if (isMethodStatic)
10
{
11
gen.Ldarg(0);
12
}
13
else
14
{
15
gen.Ldarg(1);
16
}
17
gen.Ldc(i);
18
19
Type srcType = pis[i].ParameterType;
20
string str = srcType.ToString();
21
if (str.EndsWith("&"))
22
{
23
srcType = CommonUtils.GetType(str.Substring(0, str.Length - 1));
24
}
25
26
if (str.EndsWith("&")) //ref or out param
27
{
28
if (srcType.IsValueType && (pis[i].Attributes & ParameterAttributes.Out) != ParameterAttributes.Out) //ref value param
29
{
30
gen.Ldelem(typeof(object));
31
gen.Unbox(srcType);
32
}
33
else
34
{
35
if (srcType.IsValueType && srcType != typeof(object)) //out value param
36
{
37
gen.LoadDefaultValue(srcType);
38
gen.Box(srcType);
39
gen.Stelem(typeof(object));
40
41
if (isMethodStatic)
42
{
43
gen.Ldarg(0);
44
}
45
else
46
{
47
gen.Ldarg(1);
48
}
49
gen.Ldc(i);
50
gen.Ldelem(typeof(object));
51
gen.Unbox(srcType);
52
}
53
else //ref or out class param
54
{
55
gen.Ldelema(typeof(object));
56
}
57
}
58
}
59
else
60
{
61
gen.Ldelem(typeof(object));
62
63
if (srcType.IsValueType)
64
{
65
gen.UnboxAny(srcType);
66
}
67
else if (srcType != typeof(object))
68
{
69
gen.Castclass(srcType);
70
}
71
}
72
}
73
}
74
}
75
76
private static void CastValueToObject(CodeGenerator gen, Type valueType)
77
{
78
if (valueType == typeof(void))
79
{
80
gen.Load(null);
81
}
82
else if (valueType.IsValueType)
83
{
84
gen.Box(valueType);
85
}
86
else if (valueType != typeof(object))
87
{
88
gen.Castclass(typeof(object));
89
}
90
}
代码是不是相对比较简单呢(当然是相对于自己写所有的Emit来讲的),注意这里的LoadParameter方法的实现您可以发现,为方法生成调用Delegate是完美支持输入输出参数的。
下面给出 DynamicMethodFactory类的UnitTest代码,演示了对方法、字段和属性的生成Delegate和基于Delegate的读写,且包括对输入输出参数的使用:
下载源码: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
}
namespace
CodeGeneratorUnitTest2

{3
public interface ITest4

{5
string Wow(string str);6
}7

8
public class UnitTest9

{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
}
以上代码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#region Check preconditions
7
8
Check.Require(targetModule, "targetModule");
9
Check.Require(genericMethodInfo, "genericMethodInfo");
10
Check.Require((genericParameterTypes == null && genericMethodInfo.GetGenericArguments().Length == 0) ||
11
genericParameterTypes.Length == genericMethodInfo.GetGenericArguments().Length,
12
"The number of generic type parameter of genericMethodInfo and the input types must equal!");
13
Check.Require(!genericMethodInfo.IsStatic, "genericMethodInfo must not be static here!");
14
15
#endregion
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
}
protected
static
DynamicMethodProxyHandler DoGetMethodDelegate(2
Module targetModule,3
MethodInfo genericMethodInfo,4
params
Type[] genericParameterTypes)5

{6

Check preconditions#region Check preconditions7

8
Check.Require(targetModule, "targetModule");9
Check.Require(genericMethodInfo, "genericMethodInfo");10
Check.Require((genericParameterTypes == null && genericMethodInfo.GetGenericArguments().Length == 0) ||11
genericParameterTypes.Length == genericMethodInfo.GetGenericArguments().Length,12
"The number of generic type parameter of genericMethodInfo and the input types must equal!");13
Check.Require(!genericMethodInfo.IsStatic, "genericMethodInfo must not be static here!");14

15
#endregion16

17
//Create a dynamic method proxy delegate used to call the specified methodinfo18
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
}
1
private static void LoadParameters(CodeGenerator gen, ParameterInfo[] pis, bool isMethodStatic)2

{3
Check.Require(gen, "gen");4

5
if (pis != null)6

{7
for (int i = 0; i < pis.Length; ++i)8

{9
if (isMethodStatic)10

{11
gen.Ldarg(0);12
}13
else14

{15
gen.Ldarg(1);16
}17
gen.Ldc(i);18

19
Type srcType = pis[i].ParameterType;20
string str = srcType.ToString();21
if (str.EndsWith("&"))22

{23
srcType = CommonUtils.GetType(str.Substring(0, str.Length - 1));24
}25

26
if (str.EndsWith("&")) //ref or out param27

{28
if (srcType.IsValueType && (pis[i].Attributes & ParameterAttributes.Out) != ParameterAttributes.Out) //ref value param29

{30
gen.Ldelem(typeof(object));31
gen.Unbox(srcType);32
}33
else34

{35
if (srcType.IsValueType && srcType != typeof(object)) //out value param36

{37
gen.LoadDefaultValue(srcType);38
gen.Box(srcType);39
gen.Stelem(typeof(object));40

41
if (isMethodStatic)42

{43
gen.Ldarg(0);44
}45
else46

{47
gen.Ldarg(1);48
}49
gen.Ldc(i);50
gen.Ldelem(typeof(object));51
gen.Unbox(srcType);52
}53
else //ref or out class param54

{55
gen.Ldelema(typeof(object));56
}57
}58
}59
else60

{61
gen.Ldelem(typeof(object));62

63
if (srcType.IsValueType)64

{65
gen.UnboxAny(srcType);66
}67
else if (srcType != typeof(object))68

{69
gen.Castclass(srcType);70
}71
}72
}73
}74
}75

76
private static void CastValueToObject(CodeGenerator gen, Type valueType)77

{78
if (valueType == typeof(void))79

{80
gen.Load(null);81
}82
else if (valueType.IsValueType)83

{84
gen.Box(valueType);85
}86
else if (valueType != typeof(object))87

{88
gen.Castclass(typeof(object));89
}90
}
代码是不是相对比较简单呢(当然是相对于自己写所有的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
}
namespace
DynamicMethodFactoryUnitTest2

{3
public class TestClass4

{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 StaticIntProperty30

{31
get32

{33
return StaticIntField;34
}35
set36

{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 NonStaticIntProperty57

{58
get59

{60
return NonStaticIntField;61
}62
set63

{64
NonStaticIntField = value;65
}66
}67
}68

69
public class UnitTest70

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

本文介绍了一组基于Emit动态生成代码的辅助类,包括CodeGenerator和DynamicMethodFactory。CodeGenerator封装了Emit方法,简化了操作逻辑。DynamicMethodFactory实现了第三方程序集内部类的实例化,以及通过DynamicMethod高效访问泛型方法。
3万+

被折叠的 条评论
为什么被折叠?



