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

转载 2012年03月27日 09:36:35

原文地址: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, nullnew[] { 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, nullnull);
            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, nullnew[] { 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的基本方法。这样,我们就基本可以解决遇到的大部分问题了。欢迎大家指正。

PyQt5学习笔记06----Qt Designer自定义信号emit及传参

from PyQt5 import QtWidgets,QtCore from untitled import Ui_Form import time class MyWindow(QtWid...

PyQt5学习笔记06----Qt Designer自定义信号emit及传参

[python] view plain copy from PyQt5 import QtWidgets,QtCore   from untitled import U...

PyQt5学习笔记06----Qt Designer自定义信号emit及传参

from PyQt5 import QtWidgets,QtCore   from untitled import Ui_Form   import  time        class My...

Java_基础—HashSet存储自定义对象保证元素唯一性

* A:案例演示 * 存储自定义对象,并保证元素唯一性。 * B:代码优化 * 为了减少比较,优化hashCode()代码写法。 * 最终版就是自动生成即可。...

java基础—自定义一个比较器,对TreeSet 集合中的元素按指定方法来排序(java集合六)

生活中的每一刻,不管是正经历着怎样的挣扎与挑战,或许我们都只有一个选择,虽然痛苦,却依然要快乐,并相信未来...

Java_基础—去除ArrayList中重复自定义对象元素

* 需求:ArrayList去除集合中自定义对象元素的重复值(对象的成员变量值相同) * B:注意事项 * 重写equals()方法 * contains()判断是否包含,底层依赖的是equals()...

Java_Map插入自定义数据类型保证元素唯一

Java中的Map是以Key-Value的形式进行存储的。Map对于基础类型(见下面注释) 作为Key 保证了Key的唯一性,但是如果插入自定义类型作为Key,我们就需要自己维护Map中Key的唯一性...

STL中vector容器中元素为自定义类型时的效率分析

相关背景知识:构造函数:类的特殊成员函数,当创建类对象的时候,系统自动调用构造函数,用于完成一些初始工作。特点:构造函数名与类名相同、没有返回值,返回void也不行,但可以无值返回、可以不定义构造函数...

如何利用C++ vector的sort算法对元素是自定义类型进行排序

#include #include #include #include //sort函数头文件 using namespace std; class Student { publ...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Emit创建常见元素—自定义类型
举报原因:
原因补充:

(最多只允许输入30个字)