基于CodeGenerator的Emit代码生成辅助类源码及演示
本文介绍一组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的代码
代码是不是相对比较简单呢(当然是相对于自己写所有的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![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
23
MethodInfo mi = typeof(ITest).GetMethod("Wow");
24![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
29
typeBuilder.DefineMethodOverride(wow.CurrentMethod, mi);
30![](/Images/OutliningIndicators/InBlock.gif)
31
Type testImplType = typeBuilder.CreateType();
32
ITest test = (ITest)Activator.CreateInstance(testImplType);
33
Check.Assert(test.Wow("hello") == "hello");
34
}
35
}
36
}
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](/Images/OutliningIndicators/InBlock.gif)
4
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
5
![](/Images/OutliningIndicators/InBlock.gif)
6
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
7
![](/Images/OutliningIndicators/InBlock.gif)
8
![](/Images/OutliningIndicators/InBlock.gif)
9
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
10
![](/Images/OutliningIndicators/InBlock.gif)
11
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
12
![](/Images/OutliningIndicators/InBlock.gif)
13
![](/Images/OutliningIndicators/InBlock.gif)
14
![](/Images/OutliningIndicators/InBlock.gif)
15
![](/Images/OutliningIndicators/InBlock.gif)
16
![](/Images/OutliningIndicators/InBlock.gif)
17
![](/Images/OutliningIndicators/InBlock.gif)
18
![](/Images/OutliningIndicators/InBlock.gif)
19
![](/Images/OutliningIndicators/InBlock.gif)
20
![](/Images/OutliningIndicators/InBlock.gif)
21
![](/Images/OutliningIndicators/InBlock.gif)
22
![](/Images/OutliningIndicators/InBlock.gif)
23
![](/Images/OutliningIndicators/InBlock.gif)
24
![](/Images/OutliningIndicators/InBlock.gif)
25
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
26
![](/Images/OutliningIndicators/InBlock.gif)
27
![](/Images/OutliningIndicators/InBlock.gif)
28
![](/Images/OutliningIndicators/InBlock.gif)
29
![](/Images/OutliningIndicators/InBlock.gif)
30
![](/Images/OutliningIndicators/InBlock.gif)
31
![](/Images/OutliningIndicators/InBlock.gif)
32
![](/Images/OutliningIndicators/InBlock.gif)
33
![](/Images/OutliningIndicators/InBlock.gif)
34
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
35
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
36
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
以上代码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![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
26
return (DynamicMethodProxyHandler)gen.EndMethod();
27
}
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/None.gif)
3
![](/Images/OutliningIndicators/None.gif)
4
![](/Images/OutliningIndicators/None.gif)
5
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
6
![](/Images/OutliningIndicators/ContractedSubBlock.gif)
16
![](/Images/OutliningIndicators/InBlock.gif)
17
![](/Images/OutliningIndicators/InBlock.gif)
18
![](/Images/OutliningIndicators/InBlock.gif)
19
![](/Images/OutliningIndicators/InBlock.gif)
20
![](/Images/OutliningIndicators/InBlock.gif)
21
![](/Images/OutliningIndicators/InBlock.gif)
22
![](/Images/OutliningIndicators/InBlock.gif)
23
![](/Images/OutliningIndicators/InBlock.gif)
24
![](/Images/OutliningIndicators/InBlock.gif)
25
![](/Images/OutliningIndicators/InBlock.gif)
26
![](/Images/OutliningIndicators/InBlock.gif)
27
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
![](/Images/OutliningIndicators/ContractedBlock.gif)
代码是不是相对比较简单呢(当然是相对于自己写所有的Emit来讲的),注意这里的LoadParameter方法的实现您可以发现,为方法生成调用Delegate是完美支持输入输出参数的。
下面给出DynamicMethodFactory类的UnitTest代码,演示了对方法、字段和属性的生成Delegate和基于Delegate的读写,且包括对输入输出参数的使用:
1
namespace DynamicMethodFactoryUnitTest
2
{
3
public class TestClass
4
{
5
public static void StaticReturnVoidMethod()
6
{
7
}
8![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
16
int ret = i + refInt;
17
refInt = i + 1;
18
refStr = "ref" + str;
19![](/Images/OutliningIndicators/InBlock.gif)
20
Check.Assert(refInt == 2);
21
Check.Assert(ret == 4);
22
Check.Assert(refStr == "refstr");
23![](/Images/OutliningIndicators/InBlock.gif)
24
return ret;
25
}
26![](/Images/OutliningIndicators/InBlock.gif)
27
public static int StaticIntField;
28![](/Images/OutliningIndicators/InBlock.gif)
29
public static int StaticIntProperty
30
{
31
get
32
{
33
return StaticIntField;
34
}
35
set
36
{
37
StaticIntField = value;
38
}
39
}
40![](/Images/OutliningIndicators/InBlock.gif)
41
public void NonStaticReturnVoidMethod()
42
{
43
}
44![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
54
public int NonStaticIntField;
55![](/Images/OutliningIndicators/InBlock.gif)
56
public int NonStaticIntProperty
57
{
58
get
59
{
60
return NonStaticIntField;
61
}
62
set
63
{
64
NonStaticIntField = value;
65
}
66
}
67
}
68![](/Images/OutliningIndicators/InBlock.gif)
69
public class UnitTest
70
{
71
private static DynamicMethodFactory fac = new DynamicMethodFactory();
72![](/Images/OutliningIndicators/InBlock.gif)
73
public static void TestStaticMethod()
74
{
75
StaticDynamicMethodProxyHandler handler = fac.GetStaticMethodDelegate(typeof(TestClass).GetMethod("StaticReturnVoidMethod"));
76
handler(null);
77![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
108
public static void TestNonStaticMethod()
109
{
110
TestClass obj = new TestClass();
111![](/Images/OutliningIndicators/InBlock.gif)
112
DynamicMethodProxyHandler handler = fac.GetMethodDelegate(typeof(TestClass).GetMethod("NonStaticReturnVoidMethod"));
113
handler(obj, null);
114![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
123
public static void TestNonStaticField()
124
{
125
TestClass obj = new TestClass();
126
obj.NonStaticIntField = -1;
127![](/Images/OutliningIndicators/InBlock.gif)
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![](/Images/OutliningIndicators/InBlock.gif)
136
public static void TestNonStaticProperty()
137
{
138
TestClass obj = new TestClass();
139
obj.NonStaticIntField = -1;
140![](/Images/OutliningIndicators/InBlock.gif)
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
}
![](/Images/OutliningIndicators/None.gif)
2
![](/Images/OutliningIndicators/ExpandedBlockStart.gif)
3
![](/Images/OutliningIndicators/InBlock.gif)
4
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
5
![](/Images/OutliningIndicators/InBlock.gif)
6
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
7
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
8
![](/Images/OutliningIndicators/InBlock.gif)
9
![](/Images/OutliningIndicators/InBlock.gif)
10
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
11
![](/Images/OutliningIndicators/InBlock.gif)
12
![](/Images/OutliningIndicators/InBlock.gif)
13
![](/Images/OutliningIndicators/InBlock.gif)
14
![](/Images/OutliningIndicators/InBlock.gif)
15
![](/Images/OutliningIndicators/InBlock.gif)
16
![](/Images/OutliningIndicators/InBlock.gif)
17
![](/Images/OutliningIndicators/InBlock.gif)
18
![](/Images/OutliningIndicators/InBlock.gif)
19
![](/Images/OutliningIndicators/InBlock.gif)
20
![](/Images/OutliningIndicators/InBlock.gif)
21
![](/Images/OutliningIndicators/InBlock.gif)
22
![](/Images/OutliningIndicators/InBlock.gif)
23
![](/Images/OutliningIndicators/InBlock.gif)
24
![](/Images/OutliningIndicators/InBlock.gif)
25
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
26
![](/Images/OutliningIndicators/InBlock.gif)
27
![](/Images/OutliningIndicators/InBlock.gif)
28
![](/Images/OutliningIndicators/InBlock.gif)
29
![](/Images/OutliningIndicators/InBlock.gif)
30
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
31
![](/Images/OutliningIndicators/InBlock.gif)
32
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
33
![](/Images/OutliningIndicators/InBlock.gif)
34
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
35
![](/Images/OutliningIndicators/InBlock.gif)
36
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
37
![](/Images/OutliningIndicators/InBlock.gif)
38
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
39
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
40
![](/Images/OutliningIndicators/InBlock.gif)
41
![](/Images/OutliningIndicators/InBlock.gif)
42
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
43
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
44
![](/Images/OutliningIndicators/InBlock.gif)
45
![](/Images/OutliningIndicators/InBlock.gif)
46
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
47
![](/Images/OutliningIndicators/InBlock.gif)
48
![](/Images/OutliningIndicators/InBlock.gif)
49
![](/Images/OutliningIndicators/InBlock.gif)
50
![](/Images/OutliningIndicators/InBlock.gif)
51
![](/Images/OutliningIndicators/InBlock.gif)
52
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
53
![](/Images/OutliningIndicators/InBlock.gif)
54
![](/Images/OutliningIndicators/InBlock.gif)
55
![](/Images/OutliningIndicators/InBlock.gif)
56
![](/Images/OutliningIndicators/InBlock.gif)
57
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
58
![](/Images/OutliningIndicators/InBlock.gif)
59
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
60
![](/Images/OutliningIndicators/InBlock.gif)
61
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
62
![](/Images/OutliningIndicators/InBlock.gif)
63
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
64
![](/Images/OutliningIndicators/InBlock.gif)
65
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
66
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
67
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
68
![](/Images/OutliningIndicators/InBlock.gif)
69
![](/Images/OutliningIndicators/InBlock.gif)
70
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
71
![](/Images/OutliningIndicators/InBlock.gif)
72
![](/Images/OutliningIndicators/InBlock.gif)
73
![](/Images/OutliningIndicators/InBlock.gif)
74
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
75
![](/Images/OutliningIndicators/InBlock.gif)
76
![](/Images/OutliningIndicators/InBlock.gif)
77
![](/Images/OutliningIndicators/InBlock.gif)
78
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
79
![](/Images/OutliningIndicators/InBlock.gif)
80
![](/Images/OutliningIndicators/InBlock.gif)
81
![](/Images/OutliningIndicators/InBlock.gif)
82
![](/Images/OutliningIndicators/InBlock.gif)
83
![](/Images/OutliningIndicators/InBlock.gif)
84
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
85
![](/Images/OutliningIndicators/InBlock.gif)
86
![](/Images/OutliningIndicators/InBlock.gif)
87
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
88
![](/Images/OutliningIndicators/InBlock.gif)
89
![](/Images/OutliningIndicators/InBlock.gif)
90
![](/Images/OutliningIndicators/InBlock.gif)
91
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
92
![](/Images/OutliningIndicators/InBlock.gif)
93
![](/Images/OutliningIndicators/InBlock.gif)
94
![](/Images/OutliningIndicators/InBlock.gif)
95
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
96
![](/Images/OutliningIndicators/InBlock.gif)
97
![](/Images/OutliningIndicators/InBlock.gif)
98
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
99
![](/Images/OutliningIndicators/InBlock.gif)
100
![](/Images/OutliningIndicators/InBlock.gif)
101
![](/Images/OutliningIndicators/InBlock.gif)
102
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
103
![](/Images/OutliningIndicators/InBlock.gif)
104
![](/Images/OutliningIndicators/InBlock.gif)
105
![](/Images/OutliningIndicators/InBlock.gif)
106
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
107
![](/Images/OutliningIndicators/InBlock.gif)
108
![](/Images/OutliningIndicators/InBlock.gif)
109
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
110
![](/Images/OutliningIndicators/InBlock.gif)
111
![](/Images/OutliningIndicators/InBlock.gif)
112
![](/Images/OutliningIndicators/InBlock.gif)
113
![](/Images/OutliningIndicators/InBlock.gif)
114
![](/Images/OutliningIndicators/InBlock.gif)
115
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
116
![](/Images/OutliningIndicators/InBlock.gif)
117
![](/Images/OutliningIndicators/InBlock.gif)
118
![](/Images/OutliningIndicators/InBlock.gif)
119
![](/Images/OutliningIndicators/InBlock.gif)
120
![](/Images/OutliningIndicators/InBlock.gif)
121
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
122
![](/Images/OutliningIndicators/InBlock.gif)
123
![](/Images/OutliningIndicators/InBlock.gif)
124
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
125
![](/Images/OutliningIndicators/InBlock.gif)
126
![](/Images/OutliningIndicators/InBlock.gif)
127
![](/Images/OutliningIndicators/InBlock.gif)
128
![](/Images/OutliningIndicators/InBlock.gif)
129
![](/Images/OutliningIndicators/InBlock.gif)
130
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
131
![](/Images/OutliningIndicators/InBlock.gif)
132
![](/Images/OutliningIndicators/InBlock.gif)
133
![](/Images/OutliningIndicators/InBlock.gif)
134
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
135
![](/Images/OutliningIndicators/InBlock.gif)
136
![](/Images/OutliningIndicators/InBlock.gif)
137
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
138
![](/Images/OutliningIndicators/InBlock.gif)
139
![](/Images/OutliningIndicators/InBlock.gif)
140
![](/Images/OutliningIndicators/InBlock.gif)
141
![](/Images/OutliningIndicators/InBlock.gif)
142
![](/Images/OutliningIndicators/InBlock.gif)
143
![](/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
144
![](/Images/OutliningIndicators/InBlock.gif)
145
![](/Images/OutliningIndicators/InBlock.gif)
146
![](/Images/OutliningIndicators/InBlock.gif)
147
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
148
![](/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
149
![](/Images/OutliningIndicators/ExpandedBlockEnd.gif)
DynamicMethodFactory类还可以用于以非泛型方法的调用语法调用泛型方法,在之前的一篇文章介绍过,这里就不重复了,感兴趣的朋友可以参见:改进的以非泛型方式调用泛型方法”之基于DynamicMethod的实现。
有任何问题欢迎回复讨论。
//The End