您的位置:首页 > 编程语言 > C#

秒懂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");

 

   
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: