时间:2021-05-19
我们常常有一个应用场景,由我们的C#代码,动态生成一个EXE,其应用场景可以非常多,比如软件授权,可以输入授权信息后,生成一个授权的DLL等,那如何实现这个功能呢,就要提到一个技术Emit。
Emit,可以称为发出或者产生。在Framework中,与Emit相关的类基本都存在于System.Reflection.Emit命名
空间下。可见Emit是作为反射的一个元素存在的。说道反射,大家应该都不陌生,它允许我们查看程序集的元素据,从而取得形如程序集包含哪些类型,类型包
含哪些方法等等大量的信息。但是反射也仅能够‘看',而Emit则可以在运行时动态生成代码。接下来就来看看如何用Emit生成代码。
程序集是一个或多个模块、资源文件的逻辑性分组,其次程序集是重用,安全性和版本控制的最小单元。我们所见到的DLL、EXE都可以称为一个Assembly,一个Assembly里面包含多个Module,不过通常,我们VS编译的时候,会只编译一个Module,假如在一个Assembly中要编译多个Module,则要借助csc.exe实现。
定义程序集
//定义一个程序集的名称 var asmName = new AssemblyName("MyClass");//首先就需要定义一个程序集 var defAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);定义模块,和指定程序集的保存名称
//定义一个构建类var defModuleBuilder = defAssembly.DefineDynamicModule("MyModule", "MyAssembly.dll");定义一个类 和方法
//定义一个类 var defClassBuilder =defModuleBuilder.DefineType("MyClass", TypeAttributes.Public); //定义一个方法var methodBldr = defClassBuilder.DefineMethod("MyMethod", MethodAttributes.Public, null,//返回类型 null//参数的类型 );以上通过创建,已经确定了程序集和模块,也定义了当前模块中的一个类和方法,但这个类的MyMethod方法只定义了一个声明,并没有定义实体操作,以下就需要应用到Emit技术中一个技术OpCode。
OpCode 是描述中间语言 (IL) 指令。这个指令非常多,可以查看微软官网:https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.emit.opcodes?view=netframework-4.8
通过OpCode我们可以定义方法的内容如下:
//获取IL生成器 var il = defMethodBuilder.GetILGenerator(); //定义一个字符串 il.Emit(OpCodes.Ldstr, "生成的第一个程序"); //调用一个函数 il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //返回到方法开始(返回) il.Emit(OpCodes.Ret);通过以上的定义,我们完成了一个程序集、模块、类和方法的定义,我们怎么把以上的定义的信息进行创建和保存,需要调用以下函数:
//创建类型 defClassBuilder.CreateType(); //保存程序集 defAssembly.Save("MyAssemblydll");我们可以在运行程序看到如下效果:
以下通过创建程序集,并且调用的代码如下:
using System;using System.Collections.Generic;using System.Linq;using System.Reflection;using System.Reflection.Emit;using System.Text;using System.Threading.Tasks;namespace ConsoleApp1{ class Program { static void Main(string[] args) { CreateAssembly(); LoadAssembly(); Console.ReadKey(); } public static void LoadAssembly() { var ass = AppDomain.CurrentDomain.Load("MyAssembly"); var m = ass.GetModule("MyModule"); var ts = m.GetTypes(); var t = ts.FirstOrDefault(); if (t != null) { object obj = Activator.CreateInstance(t); var me = t.GetMethod("MyMethod"); me.Invoke(obj, null); } } public static void CreateAssembly() { //定义一个程序集的名称 var asmName = new AssemblyName("MyAssembly"); //首先就需要定义一个程序集 var defAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave); //定义一个构建类 var defModuleBuilder = defAssembly.DefineDynamicModule("MyModule", "MyAssembly.dll"); //定义一个类 var defClassBuilder = defModuleBuilder.DefineType("MyClass", TypeAttributes.Public); //定义一个方法 var defMethodBuilder = defClassBuilder.DefineMethod("MyMethod", MethodAttributes.Public, null,//返回类型 null//参数类型 ); //获取IL生成器 var il = defMethodBuilder.GetILGenerator(); //定义一个字符串 il.Emit(OpCodes.Ldstr, "生成的第一个程序"); //调用一个函数 il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); //返回到方法开始(返回) il.Emit(OpCodes.Ret); //创建类型 defClassBuilder.CreateType(); //保存程序集 defAssembly.Save("MyAssembly.dll"); } }}显示效果如下:
以上就是详解c# Emit技术的详细内容,更多关于c# Emit技术的资料请关注其它相关文章!
声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。
目录Emit异常处理流程显示Exception对象的Message属性返回目录Emit异常处理流程来看这种C#异常处理代码:复制代码代码如下:staticvoi
C#动态创建button按钮的方法实例详解C#编程中经常需要动态创建,本文主要介绍C#动态创建button按钮的方法,涉及C#按钮属性动态设置的相关技巧,以供借
详解C#编程获取资源文件中图片的方法本文主要介绍C#编程获取资源文件中图片的方法,涉及C#针对项目中资源文件操作的相关技巧,以供借鉴参考。具体内容如下:例子:u
C#中Array和ArrayList详解及区别一、Array的用法type[]typename=newtype[size];或者type[]typename=n
详解C#使用AD(ActiveDirectory)验证内网用户名密码1.连到内网,找到AD的domain地址nslookupsettypes=all_ldap.