秒懂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 // create method builder
2 var methodBuilder = typeBuilder.DefineMethod(
3 "SayHelloMethod",
4 MethodAttributes.Public | MethodAttributes.Static,
5 null,
6 null);
7
8 // then get the method il generator
9 var il = methodBuilder.GetILGenerator();
10
11 // then create the method function
12 il.Emit(OpCodes.Ldstr, "Hello, Kitty!");
13 il.Emit(OpCodes.Call,
14 typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
15 il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine"));
16 il.Emit(OpCodes.Pop); // we just read something here, throw it.
17 il.Emit(OpCodes.Ret);
创建类型,
1 // then create the whole class type 2 var helloKittyClassType = typeBuilder.CreateType();
如果当前程序集是可运行的,则设置一个程序入口,
1 // set entry point for this assembly
2 assemblyBuilder.SetEntryPoint(helloKittyClassType.GetMethod("SayHelloMethod"));
将动态生成的程序集保存成磁盘文件,
1 // save assembly
2 assemblyBuilder.Save("Kitty.exe");
此时,通过反编译工具,将Kitty.exe反编译成代码,
1 using System;
2
3 public class HelloKittyClass
4 {
5 public static void SayHelloMethod()
6 {
7 Console.WriteLine("Hello, Kitty!");
8 Console.ReadLine();
9 }
10 }
运行结果,
完整代码
1 using System;
2 using System.Reflection;
3 using System.Reflection.Emit;
4
5 namespace EmitIntroduction
6 {
7 class Program
8 {
9 static void Main(string[] args)
10 {
11 // specify a new assembly name
12 var assemblyName = new AssemblyName("Kitty");
13
14 // create assembly builder
15 var assemblyBuilder = AppDomain.CurrentDomain
16 .DefineDynamicAssembly(assemblyName,
17 AssemblyBuilderAccess.RunAndSave);
18
19 // create module builder
20 var moduleBuilder =
21 assemblyBuilder.DefineDynamicModule(
22 "KittyModule", "Kitty.exe");
23
24 // create type builder for a class
25 var typeBuilder =
26 moduleBuilder.DefineType(
27 "HelloKittyClass", TypeAttributes.Public);
28
29 // create method builder
30 var methodBuilder = typeBuilder.DefineMethod(
31 "SayHelloMethod",
32 MethodAttributes.Public | MethodAttributes.Static,
33 null,
34 null);
35
36 // then get the method il generator
37 var il = methodBuilder.GetILGenerator();
38
39 // then create the method function
40 il.Emit(OpCodes.Ldstr, "Hello, Kitty!");
41 il.Emit(OpCodes.Call,
42 typeof(Console).GetMethod(
43 "WriteLine", new Type[] { typeof(string) }));
44 il.Emit(OpCodes.Call,
45 typeof(Console).GetMethod("ReadLine"));
46 il.Emit(OpCodes.Pop); // we just read something here, throw it.
47 il.Emit(OpCodes.Ret);
48
49 // then create the whole class type
50 var helloKittyClassType = typeBuilder.CreateType();
51
52 // set entry point for this assembly
53 assemblyBuilder.SetEntryPoint(
54 helloKittyClassType.GetMethod("SayHelloMethod"));
55
56 // save assembly
57 assemblyBuilder.Save("Kitty.exe");
58
59 Console.WriteLine(
60 "Hi, Dennis, a Kitty assembly has been generated for you.");
61 Console.ReadLine();
62 }
63 }
64 }


浙公网安备 33010602011771号