这个可能应该属于反射的高级使用范围了,平常在项目中使用的人估计也不是很多。
由于使用反射的话会降低性能,比如之前用到的GetValue
、SetValue
等之类,但是使用这种方式会大大提高效率,在这里我只想说,都直接写IL指令了,效率再低的话说不过去了。。。
在之前的文章中有写过一个将已经编译好的exe文件嵌入到资源文件中,然后在打开程序的时候释放出来且运行,嗯,还是一种比较简单的实现方式,这里也可以利用反射来实现这个功能,这种方式就不需要预先写好exe程序了,可以直接生成保存到本地或者在内存中运行。
其实我对IL也不熟悉,以下关于IL代码部分也是半写半猜,emmmmm,反正我也是先写c#代码然后翻译成IL的。。。
实现功能:
- 使用反射动态生成dll/exe文件
开发环境:
开发工具: Visual Studio 2013
.NET Framework版本:4.5
实现代码:
private void EmitIL()
{
AssemblyName assemblyName = new AssemblyName("Emit");
assemblyName.Version = new Version("1.0.0");
//定义一个可以执行和保存的程序集
//此处可以理解为向解决方案中添加了一个EmitTest的项目
var defAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
//定义模块
//关于模块的概念可参考:https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.module
var defModuleBuilder = defAssembly.DefineDynamicModule("EmitModule", "Emit.dll");
//定义一个公共类
var defClassBuilder = defModuleBuilder.DefineType("EmitClass", TypeAttributes.Public);
//在类中定义一个公共方法
//实现两个整数相加
var defMethodBuilder = defClassBuilder.DefineMethod("EmitMethod",
MethodAttributes.Public,
typeof(Int32),//返回类型
new Type[2] { typeof(Int32), typeof(Int32) }//参数类型
);
//获取IL生成器
var il = defMethodBuilder.GetILGenerator();
#region 方法的内容
// 这里的代码如果不知道怎么写,可以直接写c#代码,然后使用ILDASM或者其他软件反编译成IL代码,参考着写就行
//定义变量,x+y会产生一个变量,所以我认为这里需要先定义一下,否则会报错。
var xy = il.DeclareLocal(typeof(int));
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Ldarg_2);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stloc_0);
il.Emit(OpCodes.Br_S, xy);
il.Emit(OpCodes.Ldloc_0);
il.Emit(OpCodes.Ret);
#endregion
//创建类的 System.Type 对象
//如Type type = typeof(Form2);
Type type = defClassBuilder.CreateType();
//实例化
object Instance = Activator.CreateInstance(type);
//调用方法
//object obj = type.GetMethod("EmitMethod").Invoke(Instance, new object[2] { 1, 3 });
object obj = type.InvokeMember("EmitMethod", BindingFlags.InvokeMethod, null, Instance, new object[2] { 1, 3 });
MessageBox.Show(obj.ToString());
//保存程序集
defAssembly.Save("Emit.dll");
}
private void btn_emit_Click(object sender, EventArgs e)
{
EmitIL();
}
实现效果:
****
以上代码最后将程序集保存到本地了,这里可以反编译看到生成的dll的代码如下:
由简入繁,拿来即用
更多精彩,请持续关注公众号: