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

