Emit创建常见元素—自定义类型
来源:互联网 发布:淘宝 图片裁剪 不清楚 编辑:程序博客网 时间:2024/06/05 03:47
原文地址:http://www.cnblogs.com/MythYsJh/archive/2010/04/28/1723398.html
本文讲述用Emit创建枚举,结构体,类,接口等类型.
同样,让我们先搭好大体框架:
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来实现。
这里定义了一个基础类型为int,名称为Sex的public枚举。下面,让我们再为该枚举添加'内容':
enumBldr.DefineLiteral("Female", 1);
之后也需要像创建类一样使用
来完成一个枚举的创建。这是用Reflector查看就可以看到如下一个枚举了:
{
Male,
Female
}
二、结构体(struct)
在ModuleBuilder中并不存在DefineStruct之类的方法。那该如何创建一个结构体呢?我们首先用C#创建一个结构体然后反编译成IL就会发现结构体实质是继承于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代码同样可以发现接口其实也是类。因此我们还是可以想创建类一样来创建接口.
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代码却可以。因此可以如下来定义委托。
delPropertyChangedHandler.CreateType();
但是这样的定义似乎总觉得很奇怪,因为委托还包含返回值及参数等信息,这些在这段代码都没有得到体现。那么该如何创建委托呢?让我们还是从现有的入手,以EventHandler为例,在Reflector下它的结构为
事实上,创建委托必须包含一个构造函数和Invoke方法。Invoke方法的参数则是委托的参数,返回类型即为委托的返回类型。
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即可.
//其余部分
typeBldr.DefineEvent("OnNameChanged", EventAttributes.None, delType);
typeBldr.CreateType();
六、小结
我们已经可以用Emit创建常见元素了。当然,Emit还可以创建很多其他内容,不可能介绍完全,关键是要掌握通过C#和IL对比来完成Emit的基本方法。这样,我们就基本可以解决遇到的大部分问题了。欢迎大家指正。
- Emit创建常见元素—自定义类型
- Emit学习之旅(2):创建常见元素—基础部分
- Emit进阶 创建自定义委托Delegate
- UMLet创建自定义元素
- 创建自定义账户类型
- 创建自定义查找类型
- 创建自定义Qt类型
- 如何创建QML自定义元素?
- 创建自定义的Polymer元素
- 自定义createElement——根据html字符串创建元素
- 创建自定义的DataObject类型
- Qt之创建自定义类型
- std::map find 自定义类型元素
- C++中常见类型转换自定义函数
- WebServices 动态调用 接口自动创建 EMIT
- Unity3D ShaderLab 创建自定义高光类型
- 创建自定义类型的强类型化集合
- 创建自定义类型的强类型化集合
- 建立Windows Embedded Compact 7开发环境
- SAX解析实例
- DOM4J解析实例
- 系统调用3
- EJB学习总结
- Emit创建常见元素—自定义类型
- POJ 1873 The Fortified Forest 凸包+枚举
- 关于字符串缓冲池的讨论
- 简易C/C++日志
- JAVA操纵XML 实例讲解
- Ubuntu 下nfs服务器的配置及mini2440的挂载
- IOS开发之UIFont应用
- 图解框架-跨平台应用开发方案
- java 字符串 String 的缓冲池