標籤:
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 //Emit12 /*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 start20 */21 //STEP 1. Give him a name22 var assemblyName = new AssemblyName("PersonMoudle");23 24 //STEP 2. Build a assembly25 var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName,26 AssemblyBuilderAccess.RunAndSave);27 28 //STEP 3. Add a moudle29 var moudle = assemblyBuilder.DefineDynamicModule("PersonMoudle", "PersonMoudle.dll");30 31 //SETP 4. Add a Class32 var typePart = moudle.DefineType("Person", TypeAttributes.Public);33 34 //SETP 5. Add a method for this Class35 var methodPart = typePart.DefineMethod("SayHi", MethodAttributes.Public, null, null);36 37 //STEP 6. Imp the method38 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 //再比如,構建一個exe46 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的執行效果:
C#中反射的使用(How to use reflect in CSharp)(3)Emit的使用