zoukankan      html  css  js  c++  java
  • c# Emit技术解析

    我们常常有一个应用场景,由我们的C#代码,动态生成一个EXE,其应用场景可以非常多,比如软件授权,可以输入授权信息后,生成一个授权的DLL等,那如何实现这个功能呢,就要提到一个技术Emit。

    1、Emit概述

    Emit,可以称为发出或者产生。在Framework中,与Emit相关的类基本都存在于System.Reflection.Emit命名
    空间下。可见Emit是作为反射的一个元素存在的。说道反射,大家应该都不陌生,它允许我们查看程序集的元素据,从而取得形如程序集包含哪些类型,类型包
    含哪些方法等等大量的信息。但是反射也仅能够‘看’,而Emit则可以在运行时动态生成代码。接下来就来看看如何用Emit生成代码。

    2、程序集(Assembly)和模块(Managed Module)

    程序集是一个或多个模块、资源文件的逻辑性分组,其次程序集是重用,安全性和版本控制的最小单元。我们所见到的DLL、EXE都可以称为一个Assembly,一个Assembly里面包含多个Module,不过通常,我们VS编译的时候,会只编译一个Module,假如在一个Assembly中要编译多个Module,则要借助csc.exe实现。

    3、动态生成代码操作

    • 定义程序集
      //定义一个程序集的名称
     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");
            }
    
        }
    }

    显示效果如下:

  • 相关阅读:
    随 机 贪 心
    QWidget,QMainWindow和QDialog的区别
    粒子系统和Ogre 3D扩展 -----OGRE 3D 1.7 Beginner‘s Guide中文版 第十章(终章)
    setStyleSheet 设置多个属性
    Ogre 3D的启动顺序 -----OGRE 3D 1.7 Beginner‘s Guide中文版 第九章
    合成器框架 -----OGRE 3D 1.7 Beginner‘s Guide中文版 第八章
    Ogre 3D与材质 -----OGRE 3D 1.7 Beginner‘s Guide中文版 第七章
    场景管理器 -----OGRE 3D 1.7 Beginner‘s Guide中文版 第六章
    使用Ogre 3D 运动模型 -----OGRE 3D 1.7 Beginner‘s Guide中文版 第五章
    摄像机,光源和阴影 -----OGRE 3D 1.7 Beginner‘s Guide中文版 第四章
  • 原文地址:https://www.cnblogs.com/minhost/p/12190865.html
Copyright © 2011-2022 走看看