基于CodeGenerator的Emit代码生成辅助类源码及

系统 1819 0
本文介绍一组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代码:

 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了一个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
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的代码

代码是不是相对比较简单呢(当然是相对于自己写所有的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     }

DynamicMethodFactory类还可以用于以非泛型方法的调用语法调用泛型方法,在之前的一篇文章介绍过,这里就不重复了,感兴趣的朋友可以参见: 改进的 以非泛型方式调用泛型方法”之基于DynamicMethod的实现

有任何问题欢迎回复讨论。

//The End

基于CodeGenerator的Emit代码生成辅助类源码及演示


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论