秒懂C#通过Emit动态生成代码 C#使用Emit构造拦截器动态代理类
2018-04-15 02:08
357 查看
秒懂C#通过Emit动态生成代码
首先需要声明一个程序集名称,
1 // specify a new assembly name 2 var assemblyName = new AssemblyName("Kitty");
从当前应用程序域获取程序集构造器,
1 // create assembly builder 2 var assemblyBuilder = AppDomain.CurrentDomain 3 .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
有几种动态程序集构造访问限制:
- AssemblyBuilderAccess.Run; 表示程序集可被执行,但不能被保存。
- AssemblyBuilderAccess.Save; 表示程序集可被保存,但不能被执行。
- AssemblyBuilderAccess.RunAndSave; 表示程序集可被保存并能被执行。
- AssemblyBuilderAccess.ReflectionOnly; 表示程序集只能用于反射上下文环境中,不能被执行。
- AssemblyBuilderAccess.RunAndCollect; 表示程序集可以被卸载并且内存会被回收。
在程序集中构造动态模块,
1 // create module builder 2 var moduleBuilder = assemblyBuilder.DefineDynamicModule("KittyModule", "Kitty.exe");
模块即是代码的集合,一个程序集中可以有多个模块。并且理论上讲,每个模块可以使用不同的编程语言实现,例如C#/VB。
构造一个类型构造器,
1 // create type builder for a class 2 var typeBuilder = moduleBuilder.DefineType("HelloKittyClass", TypeAttributes.Public);
通过类型构造器定义一个方法,获取方法构造器,获得方法构造器的IL生成器,通过编写IL代码来定义方法功能。
1 using system; 2 using system.linq; 3 using system.reflection; 4 using system.reflection.emit; 5 6 namespace emitcreatedynamicproxy 7 { 8 class program 9 { 10 static void main(string[] args) 11 { 12 var command = proxy.of<command>(); 13 command.execute(); 14 15 console.writeline("hi, dennis, great, we got the interceptor works."); 16 console.readline(); 17 } 18 } 19 20 public class command 21 { 22 public virtual void execute() 23 { 24 console.writeline("command executing..."); 25 console.writeline("hello kitty!"); 26 console.writeline("command executed."); 27 } 28 } 29 30 public class interceptor 31 { 32 public object invoke(object @object, string @method, object[] parameters) 33 { 34 console.writeline( 35 string.format("interceptor does something before invoke [{0}]...", @method)); 36 37 var retobj = @object.gettype().getmethod(@method).invoke(@object, parameters); 38 39 console.writeline( 40 string.format("interceptor does something after invoke [{0}]...", @method)); 41 42 return retobj; 43 } 44 } 45 46 public class proxy 47 { 48 public static t of<t>() where t : class, new() 49 { 50 string nameofassembly = typeof(t).name + "proxyassembly"; 51 string nameofmodule = typeof(t).name + "proxymodule"; 52 string nameoftype = typeof(t).name + "proxy"; 53 54 var assemblyname = new assemblyname(nameofassembly); 55 var assembly = appdomain.currentdomain 56 .definedynamicassembly(assemblyname, assemblybuilderaccess.run); 57 var modulebuilder = assembly.definedynamicmodule(nameofmodule); 58 59 var typebuilder = modulebuilder.definetype( 60 nameoftype, typeattributes.public, typeof(t)); 61 62 injectinterceptor<t>(typebuilder); 63 64 var t = typebuilder.createtype(); 65 66 return activator.createinstance(t) as t; 67 } 68 69 private static void injectinterceptor<t>(typebuilder typebuilder) 70 { 71 // ---- define fields ---- 72 73 var fieldinterceptor = typebuilder.definefield( 74 "_interceptor", typeof(interceptor), fieldattributes.private); 75 76 // ---- define costructors ---- 77 78 var constructorbuilder = typebuilder.defineconstructor( 79 methodattributes.public, callingconventions.standard, null); 80 var ilofctor = constructorbuilder.getilgenerator(); 81 82 ilofctor.emit(opcodes.ldarg_0); 83 ilofctor.emit(opcodes.newobj, typeof(interceptor).getconstructor(new type[0])); 84 ilofctor.emit(opcodes.stfld, fieldinterceptor); 85 ilofctor.emit(opcodes.ret); 86 87 // ---- define methods ---- 88 89 var methodsoftype = typeof(t).getmethods(bindingflags.public | bindingflags.instance); 90 91 for (var i = 0; i < methodsoftype.length; i++) 92 { 93 var method = methodsoftype[i]; 94 var methodparametertypes = 95 method.getparameters().select(p => p.parametertype).toarray(); 96 97 var methodbuilder = typebuilder.definemethod( 98 method.name, 99 methodattributes.public | methodattributes.virtual, 100 callingconventions.standard, 101 method.returntype, 102 methodparametertypes); 103 104 var ilofmethod = methodbuilder.getilgenerator(); 105 ilofmethod.emit(opcodes.ldarg_0); 106 ilofmethod.emit(opcodes.ldfld, fieldinterceptor); 107 108 // create instance of t 109 ilofmethod.emit(opcodes.newobj, typeof(t).getconstructor(new type[0])); 110 ilofmethod.emit(opcodes.ldstr, method.name); 111 112 // build the method parameters 113 if (methodparametertypes == null) 114 { 115 ilofmethod.emit(opcodes.ldnull); 116 } 117 else 118 { 119 var parameters = ilofmethod.declarelocal(typeof(object[])); 120 ilofmethod.emit(opcodes.ldc_i4, methodparametertypes.length); 121 ilofmethod.emit(opcodes.newarr, typeof(object)); 122 ilofmethod.emit(opcodes.stloc, parameters); 123 124 for (var j = 0; j < methodparametertypes.length; j++) 125 { 126 ilofmethod.emit(opcodes.ldloc, parameters); 127 ilofmethod.emit(opcodes.ldc_i4, j); 128 ilofmethod.emit(opcodes.ldarg, j + 1); 129 ilofmethod.emit(opcodes.stelem_ref); 130 } 131 ilofmethod.emit(opcodes.ldloc, parameters); 132 } 133 134 // call invoke() method of interceptor 135 ilofmethod.emit(opcodes.callvirt, typeof(interceptor).getmethod("invoke")); 136 137 // pop the stack if return void 138 if (method.returntype == typeof(void)) 139 { 140 ilofmethod.emit(opcodes.pop); 141 } 142 143 // complete 144 ilofmethod.emit(opcodes.ret); 145 } 146 } 147 } 148 }view code
下载完整代码
搜索此文相关文章:C#使用Emit构造拦截器动态代理类
此文链接:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%8E%A8%E8%8D%90/30505.shtml
转载请注明出处:C#使用Emit构造拦截器动态代理类 - 博客园
C#反射发出System.Reflection.Emit学习
一、System.Reflection.Emit概述
Emit,可以称为发出或者产生。与Emit相关的类基本都存在于System.Reflection.Emit命名空间下。反射,我们可以取得形如程序集包含哪些类型,类型包含哪些方法等等大量的信息,而Emit则可以在运行时动态生成代码。
二、IL代码解析
以下代码为例:
1 var asmName = new AssemblyName("Test"); 2 3 var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( 4 5 asmName, 6 7 AssemblyBuilderAccess.RunAndSave); 8 9 var mdlBldr = asmBuilder.DefineDynamicModule("Main", "Main.exe"); 10 11 var typeBldr = mdlBldr.DefineType("Hello", TypeAttributes.Public); 12 13 var methodBldr = typeBldr.DefineMethod( 14 15 "SayHello", 16 17 MethodAttributes.Public | MethodAttributes.Static, 18 19 null,//return type 20 21 null//parameter type 22 23 ); 24 25 var il = methodBldr.GetILGenerator();//获取il生成器 26 27 il.Emit(OpCodes.Ldstr,"Hello, World"); 28 29 il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]{typeof(string)})); 30 31 il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine")); 32 33 il.Emit(OpCodes.Pop);//读入的值会被推送至evaluation stack,而本方法是没有返回值的,因此,需要将栈上的值抛弃 34 35 il.Emit(OpCodes.Ret); 36 37 var t = typeBldr.CreateType(); 38 39 asmBuilder.SetEntryPoint(t.GetMethod("SayHello")); 40 41 asmBuilder.Save("Main.exe");
相关文章推荐
- 秒懂C#通过Emit动态生成代码
- C#动态生成代码和程序集
- 通过C#动态生成图书信息XML文件
- 如何用C#动态生成代码
- Windows Phone 7使用C#通过后台动态生成Grid网格布局
- C# 通过T4自动生成代码
- 如何用C#动态生成代码
- C#动态生成代码和程序集
- Unity3d 通过json文件使用C#脚本代码生成多个相机
- C# 实现 Aop [Emit动态生成代理类方式]
- Android学习笔记_31_通过后台代码生成View对象以及动态加载XML布局文件到LinearLayout
- Emit动态生成代码
- 动态生成鼠标指针--可以利用已有的图片生成鼠标指针--C#代码
- C#动态生成代码——CodeDom
- C#版本的备案接口pwdHash生成代码(测试通过)
- Android 通过Java代码生成创建界面。动态生成View,动态设置View属性。addRules详解
- c#语言asp.net实现treeview控件读数据库动态生成树的代码
- Android学习笔记_31_通过后台代码生成View对象以及动态加载XML布局文件到LinearLayout
- c#语言asp.net实现treeview控件读数据库动态生成树的代码
- C#代码生成控件动态效果-XAML篇