码迷,mamicode.com
首页 > 其他好文 > 详细

反射-Emit

时间:2018-07-07 20:23:10      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:win   framework   read   eval   deb   pdo   domain   point   test   

一、Emit

Emit,可以称为发出或者产出。在Framework中,与Emit相关的类基本都存在与System.Reflection,Emit命名空间下。可见Emit是作为反射的一个元素存在,反射可以查看程序集的元数据,获取程序集包含哪些类型,类型包含哪些方法等,但是反射只能“看”,Emit可以在运行时动态生成代码(IL),.net就可以执行。反射主要用到对象已经存在的情况下,而反射发出主要用到对象并不存在等情况下(而利用代码动态的构建对象)。

二、动态生成代码(IL代码)

1.构建程序集

var as = new AssemblyName("TEST");

//AssemblyBuilderAccess.RunAndSave 表示动态程序集会被保存至磁盘并能立即执行。

var  asmBuilder=AppDomain.CurrentDomain.DefineDynamicAssembly(asmName,AssemblyBuilderAccess.RunAndSave);

AssemblyBuilderAccess,ReflectionOnly;

 

2.创建模块

var mdlBldr = asmBuilder.DefineDynamicModult("Main","Main.dll");

 

3.定义类

var typeBldr=mdlBldr.DefineType("Hello",TypeAttributes.Public);

4.定义类成员

var  methodBldr = typeBldr.DefineMethod(

"SayHello",

MethodAttributes.Public,

null,//返回类型

null//参数类型

)

方法的原型即为 SayHello

Console.WriteLine("Hello World");

var i = methodBldr.GetILGenerator();//获取IL生成器

il.Emit(OpCodes.Ldstr,"Hello, World"); 
il.Emit(OpCodes.Call,typeof(Console).GetMethod("WriteLine",new Type[]{typeof(string)})); 
il.Emit(OpCodes.Ret);

  OpCodes枚举定义了所有可能的操作,这里用到了:

  ldStr:加载一个字符串到evaluation stack。

  Call:调用方法。

  Ret:返回,当evaluation stack有值时会返回栈顶值。

  完成上面的步骤,一个类型好像就已经完成了。事实上却还没有,最后我们还必须显示的调用CreateType来完成类型的创建。

typeBldr.CreateType();

  这样一个完整的类就算完成了。但为了能用reflector查看我们创建的动态程序集,我们选择将这个程序集保存下来。

asmBuilder.Save("Main.dll");

   如前面定义模块时所说,这里文件名字必须和模块保存到的文件一致,否则我们前面定义的模块和这个模块的一切就无家可归了。接下来,(如果在定义模块时未指定动态创建的程序要保存到哪个目录)我们就可以到 Debug目录下看看生成的Main.dll了,用Reflector打开可以看到:

 

  三、不包含main的控制台程序

  一直以来,应用程序(控制台,winform)都是从Main函数启动的,如果没有Main还能启动吗?答案是可以,下面就用emit来做这样一个控制台程序,完整代码如下:

var asmName = new AssemblyName("Test"); 
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( 
asmName, 
AssemblyBuilderAccess.RunAndSave); 
var mdlBldr = asmBuilder.DefineDynamicModule("Main", "Main.exe"); 
var typeBldr = mdlBldr.DefineType("Hello", TypeAttributes.Public); 
var methodBldr = typeBldr.DefineMethod( 
"SayHello", 
MethodAttributes.Public | MethodAttributes.Static, 
null,//return type 
null//parameter type 
); 
var il = methodBldr.GetILGenerator();//获取il生成器 
il.Emit(OpCodes.Ldstr,"Hello, World"); 
il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[]{typeof(string)})); 
il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine")); 
il.Emit(OpCodes.Pop);//读入的值会被推送至evaluation stack,而本方法是没有返回值的,因此,需要将栈上的值抛弃 
il.Emit(OpCodes.Ret); 
var t = typeBldr.CreateType(); 
asmBuilder.SetEntryPoint(t.GetMethod("SayHello")); 
asmBuilder.Save("Main.exe");

运行生成的Main.exe效果如下:

 

反射-Emit

标签:win   framework   read   eval   deb   pdo   domain   point   test   

原文地址:https://www.cnblogs.com/whl4835349/p/9277665.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!