Emit创建常见元素—自定义类型

原文地址:http://www.cnblogs.com/MythYsJh/archive/2010/04/28/1723398.html

本文讲述用Emit创建枚举,结构体,类,接口等类型.

  同样,让我们先搭好大体框架:

            AssemblyName assemName  =   new  AssemblyName();
            assemName.Name 
=   " EmitStudy3 " ;

            AssemblyBuilder asmBuilder 
=
               AppDomain.CurrentDomain.DefineDynamicAssembly(assemName,
                  AssemblyBuilderAccess.RunAndSave);

            var mdlBldr 
=  asmBuilder.DefineDynamicModule( " EmitStudy3 " " EmitStudy3.dll " );

            
// TODO:添加自定义类型

            asmBuilder.Save(
" EmitStudy3.dll " );

 

一、创建枚举

  枚举通过ModuleBuilder.DefineEnum来实现。

       var enumBldr  =  mdlBldr.DefineEnum( " Sex " , TypeAttributes.Public,  typeof ( int ));

 

  这里定义了一个基础类型为int,名称为Sex的public枚举。下面,让我们再为该枚举添加'内容':

            enumBldr.DefineLiteral( " Male " 0 );
            enumBldr.DefineLiteral(
" Female " 1 );

 

  之后也需要像创建类一样使用

            enumBldr.CreateType();

 

来完成一个枚举的创建。这是用Reflector查看就可以看到如下一个枚举了:

public   enum  Sex
{
    Male,
    Female
}

 

 

 

  二、结构体(struct)

  在ModuleBuilder中并不存在DefineStruct之类的方法。那该如何创建一个结构体呢?我们首先用C#创建一个结构体然后反编译成IL就会发现结构体实质是继承于ValueType的一个类。因此我们可以这样来创建一个结构体:

            var nameStruct  =  mdlBldr.DefineType( " Name " , TypeAttributes.Public,  typeof (ValueType));
            var fldFirstName 
=  nameStruct.DefineField( " FirstName " typeof ( string ), FieldAttributes.Private);
            var fldLastName 
=  nameStruct.DefineField( " LastName " typeof ( string ), FieldAttributes.Private);

            var methodGetFirstName 
=  nameStruct.DefineMethod( " GetFirstName " , MethodAttributes.Public, CallingConventions.Standard,  typeof ( string ),  null );
            var methodSetFirstName 
=  nameStruct.DefineMethod( " SetFirstName " , MethodAttributes.Public, CallingConventions.Standard,  null , new  []{  typeof ( string )});

            var ilGetFirstName 
=  methodGetFirstName.GetILGenerator();
            ilGetFirstName.Emit(OpCodes.Ldarg_0);
            ilGetFirstName.Emit(OpCodes.Ldfld, fldFirstName);
            ilGetFirstName.Emit(OpCodes.Ret);

            var ilSetFirstName 
=  methodSetFirstName.GetILGenerator();
            ilSetFirstName.Emit(OpCodes.Ldarg_0);
            ilSetFirstName.Emit(OpCodes.Ldarg_1);
            ilSetFirstName.Emit(OpCodes.Stfld, fldFirstName);
            ilSetFirstName.Emit(OpCodes.Ret);

            var prptFirstName 
=  nameStruct.DefineProperty( " FirstName " , PropertyAttributes.None,  typeof ( string ),  null );
            prptFirstName.SetGetMethod(methodGetFirstName);
            prptFirstName.SetSetMethod(methodSetFirstName);

            var methodGetLastName 
=  nameStruct.DefineMethod( " GetLastName " , MethodAttributes.Public, CallingConventions.Standard,  typeof ( string ),  null );
            var methodSetLastName 
=  nameStruct.DefineMethod( " SetLastName " , MethodAttributes.Public, CallingConventions.Standard,  null new [] {  typeof ( string ) });

            var ilGetLastName 
=  methodGetLastName.GetILGenerator();
            ilGetLastName.Emit(OpCodes.Ldarg_0);
            ilGetLastName.Emit(OpCodes.Ldfld, fldLastName);
            ilGetLastName.Emit(OpCodes.Ret);

            var ilSetLastName 
=  methodSetLastName.GetILGenerator();
            ilSetLastName.Emit(OpCodes.Ldarg_0);
            ilSetLastName.Emit(OpCodes.Ldarg_1);
            ilSetLastName.Emit(OpCodes.Stfld, fldLastName);
            ilSetLastName.Emit(OpCodes.Ret);

            var prptLastName 
=  nameStruct.DefineProperty( " LastName " , PropertyAttributes.None,  typeof ( string ),  null );
            prptLastName.SetGetMethod(methodGetLastName);
            prptLastName.SetSetMethod(methodSetLastName);

            nameStruct.CreateType();

 

  上面就创建了一个包含FirstName和LastName的结构体Name。

  

  三、创建接口

  同样在ModuleBuilder中也没有DefineInterface这样的方法。而通过观察IL代码同样可以发现接口其实也是类。因此我们还是可以想创建类一样来创建接口.

            var iStudentBldr  =  mdlBldr.DefineType( " IStudent " , TypeAttributes.Public |  TypeAttributes.Interface  |  TypeAttributes.Abstract,  null );
            iStudentBldr.DefineMethod(
" Update " , MethodAttributes.Virtual  |  MethodAttributes.Abstract,  null null );
            iStudentBldr.CreateType();

 

这样就创建了一个仅包含一个Update方法的接口IStudent。在创建接口时也要注意TypeAttributes需声明为 TypeAttributes.Interface | TypeAttributes.Abstract,而接口包含的方法的MethodAttributes则必须为MethodAttributes.Virtual | MethodAttributes.Abstract

  

  四、创建类

  已经有很多这方面的例子,这里就不再赘述。

 

  五、委托和事件

  老规矩,从反编译的IL代码入手。可以发现我们创建的委托其实是派生自MultiDelegate类的类。而MultiDelegate这个类比较特殊,它不能从C#代码里被继承,但在IL代码却可以。因此可以如下来定义委托。

            var delPropertyChangedHandler  =  mdlBldr.DefineType( " PropertyChanedHandler " , TypeAttributes.Public,  typeof (MulticastDelegate));
            delPropertyChangedHandler.CreateType();

 

  但是这样的定义似乎总觉得很奇怪,因为委托还包含返回值及参数等信息,这些在这段代码都没有得到体现。那么该如何创建委托呢?让我们还是从现有的入手,以EventHandler为例,在Reflector下它的结构为

     

      事实上,创建委托必须包含一个构造函数和Invoke方法。Invoke方法的参数则是委托的参数,返回类型即为委托的返回类型。

            var delPropertyChangedHandler  =  mdlBldr.DefineType( " PropertyChanedHandler " , TypeAttributes.Public  |  TypeAttributes.Sealed,  typeof (MulticastDelegate));
            var constructor 
=  delPropertyChangedHandler.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard,  new [] {  typeof ( object ),  typeof (IntPtr) });
            constructor.SetImplementationFlags(MethodImplAttributes.Runtime 
|  MethodImplAttributes.Managed);

            var methodInvoke 
=  delPropertyChangedHandler.DefineMethod( " Invoke " , MethodAttributes.Public  |  MethodAttributes.Virtual,  null new [] {  typeof ( string ) });
            methodInvoke.SetImplementationFlags(MethodImplAttributes.Managed 
|  MethodImplAttributes.Runtime);

            var delType = delPropertyChangedHandler.CreateType();

 

构造函数和Invoke方法都使用了SetImplementationFlags(MethodImplAttributes.Managed | MethodImplAttributes.Runtime),因为二者的方法体是在运行时才能决定的。

       既然已经创建了委托,让我们再用此委托添加一个事件。定义事件就相对容易些了,直接使用TypeBuilder.DefineEvent即可.

          var typeBldr  =  mdlBldr.DefineType( " Sdudent " , TypeAttributes.Public);
          
// 其余部分
          typeBldr.DefineEvent( " OnNameChanged " , EventAttributes.None, delType);
          typeBldr.CreateType();

 

 

六、小结

      我们已经可以用Emit创建常见元素了。当然,Emit还可以创建很多其他内容,不可能介绍完全,关键是要掌握通过C#和IL对比来完成Emit的基本方法。这样,我们就基本可以解决遇到的大部分问题了。欢迎大家指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值