基于CodeGenerator的Emit代碼生成輔助類源碼及
系統(tǒng)
2212 0
本文介紹一組NBearV4中的基于Emit動(dòng)態(tài)生成代碼的輔助類,部分概念在本人的blog之前的文章中或多或少都有介紹,這里包含最新的更新及演示、測試。主要是兩個(gè)類:CodeGenerator和
DynamicMethodFactory。前者提供了一種經(jīng)過封裝的,簡化Emit方法(包括Emit DynamicMethod,Constructor,Method,get、set Method of Property)的方案;后者基于前者,實(shí)現(xiàn)了一種訪問指定類(可以是第三方程序集的internal類)的方法或成員變量,實(shí)例化第三方程序集中的internal類型,高性能的以非泛型語法訪問泛型方法的機(jī)制(通過DynamicMethod和Delegate實(shí)現(xiàn))。
下載源碼:
NBear.Common.zip
介紹
CodeGenerator
該類很多地方參照了.NET 3.0的System.Runtime.Serialization.dll中的同名internal類,他封裝了Emit中的各種Emit層面的常用操作邏輯,包括Ld各種value、成員變量,if-else,case switch,loop等分支控制等,擴(kuò)展的版本使用DesignByContract對所有的輸入?yún)?shù)進(jìn)行了檢查,并擴(kuò)展了對Emit Constructor,Method,get、set Method of Property的支持。
關(guān)于Emit DynamicMethod的示例,大家可以參見稍后介紹的
DynamicMethodFactory
類,這里先給出一個(gè)使用該類Emit一個(gè)類,并實(shí)現(xiàn)一個(gè)接口的示例代碼,該示例代碼為包含于源碼的
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
????}
以上代碼Emit了一個(gè)TestImpl類,它實(shí)現(xiàn)了ITest接口,包含一個(gè)默認(rèn)構(gòu)造函數(shù)和一個(gè)Wow方法,注意,構(gòu)造函數(shù)和方法都是通過CodeGenerator Emit的,這里的邏輯比較簡單,但應(yīng)該已經(jīng)能看到相對于ilGen.Emit(OpCodes.XXX, YYY)這樣的語法的簡化,如果實(shí)現(xiàn)邏輯復(fù)雜,對整個(gè)Emit過程的簡化就更明顯。
DynamicMethodFactory
該類的主要功能包括:實(shí)例化第三方程序集中的internal類型(
DynamicMethodFactory.
CreateInstance()方法),為指定類型(可以是第三方程序集中的internal類型)的泛型或非泛型方法、屬性、字段的讀寫生成非強(qiáng)類型的Delegate(通過DynamicMethod實(shí)現(xiàn),不使用反射,性能接近直接訪問)。
下面先給出一個(gè)該類中為一個(gè)Method創(chuàng)建一個(gè)DynamicMethod,并返回其Delegate的示例,DynamicMethod是使用前面介紹的CodeGenerator實(shí)現(xiàn)的:
?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
????????}
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
????????}
代碼是不是相對比較簡單呢(當(dāng)然是相對于自己寫所有的Emit來講的),注意這里的LoadParameter方法的實(shí)現(xiàn)您可以發(fā)現(xiàn),為方法生成調(diào)用Delegate是完美支持輸入輸出參數(shù)的。
下面給出
DynamicMethodFactory類的UnitTest代碼,演示了對方法、字段和屬性的生成Delegate和基于Delegate的讀寫,且包括對輸入輸出參數(shù)的使用:
??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
????}
DynamicMethodFactory類還可以用于以非泛型方法的調(diào)用語法調(diào)用泛型方法,在之前的一篇文章介紹過,這里就不重復(fù)了,感興趣的朋友可以參見:
改進(jìn)的
以非泛型方式調(diào)用泛型方法”之基于DynamicMethod的實(shí)現(xiàn)
。
有任何問題歡迎回復(fù)討論。
//The End
基于CodeGenerator的Emit代碼生成輔助類源碼及演示
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元