本文介绍一组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实现的:
代码是不是相对比较简单呢(当然是相对于自己写所有的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 }
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 }
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 }
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 }
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