Emit意在动态构建一个可以执行(当然也就可以反射)或者只可以反射的动态库。
个人认为在不得不使用反射的情况下,使用Emit会使得效率提升空间很大。亦或者动态插件模式的软件设计中会用到。
依然2%的废话和98%的代码:
1 using System; 2 using System.Reflection; 3 using System.Reflection.Emit; 4 5 namespace ReflectionTest 6 { 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 //Emit 12 /* 13 Emit的知识隶属于反射的一部分,也是比较偏门的一部分。 14 在出现Dynamic和匿名类之后,它会有更小的用武之地,但仍然属于Reflection的知识范畴。 15 区别于“正常”的反射,Emit是动态的构建一个类, 16 比如,现在你没有Person.Dll,没有项目可以引用,没有可以反射的对象 17 那么你可能会想到Emit,它可以使你用代码构建出一个Person类,你甚至可以把动态构建的类保存成DLL,然后使用反射调用 18 虽然也是用C#去实现,但语法风格大不相同,强硬的理解,可以理解Emit暴漏给C#一些接口,让你去操作IL,然后生成动态库 19 在这次的blog中,我们的目的就是用代码构建出这个person类。OK,Let's start 20 */ 21 //STEP 1. Give him a name 22 var assemblyName = new AssemblyName("PersonMoudle"); 23 24 //STEP 2. Build a assembly 25 var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, 26 AssemblyBuilderAccess.RunAndSave); 27 28 //STEP 3. Add a moudle 29 var moudle = assemblyBuilder.DefineDynamicModule("PersonMoudle", "PersonMoudle.dll"); 30 31 //SETP 4. Add a Class 32 var typePart = moudle.DefineType("Person", TypeAttributes.Public); 33 34 //SETP 5. Add a method for this Class 35 var methodPart = typePart.DefineMethod("SayHi", MethodAttributes.Public, null, null); 36 37 //STEP 6. Imp the method 38 var il = methodPart.GetILGenerator(); 39 il.EmitWriteLine("Hi! I'm SayHi method!"); 40 il.Emit(OpCodes.Ret); 41 42 typePart.CreateType(); 43 assemblyBuilder.Save("PersonMoudle.dll"); 44 45 //再比如,构建一个exe 46 var ad = AppDomain.CurrentDomain; 47 var am = new AssemblyName {Name = "TestEmit"}; 48 var ab = ad.DefineDynamicAssembly(am, AssemblyBuilderAccess.Save); 49 var mb = ab.DefineDynamicModule("testmod", "输出一句话.exe"); 50 var tb = mb.DefineType("TestEmit.Test", TypeAttributes.Public); 51 var metb = tb.DefineMethod("ConsoleWord", MethodAttributes.Public | MethodAttributes.Static, typeof (void), 52 null); 53 ab.SetEntryPoint(metb); 54 ILGenerator il1 = metb.GetILGenerator(); 55 il1.EmitWriteLine("Hello World"); 56 il1.EmitWriteLine("按任意键退出……"); 57 il1.Emit(OpCodes.Call, typeof (Console).GetMethod("ReadKey",new Type[]{}));//指定无参数的重载。生产环境的代码中应该有更加严格判断,具体指定个某个方法请翻前篇的文章。 58 il1.Emit(OpCodes.Ret); 59 tb.CreateType(); 60 ab.Save("输出一句话.exe"); 61 Console.ReadKey(); 62 } 63 } 64 }
我们可以看到,执行完这个之后,在Debug里会生成我们想要的PersonMoudle.dll和输出一句话.exe、反编译后的dll和exe的执行效果: