.NET Core - ILGenerator.Emit (一)

官网地址:https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.emit.ilgenerator.emit?view=netcore-3.1

一、认识 Emit

  

   使用Emit方法可以以编写C#代码的方式生成IL代码并执行 。

二、简单使用

   Example:创建程序集、创建模块、创建类、创建构造函数、创建方法并调用

static void Main(string[] args)
{
    // -- 创建程序集
    AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("Example.Generator"), AssemblyBuilderAccess.RunAndCollect);
    // -- 创建模块
    ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Generators");
    // -- 创建 Generator 类
    TypeBuilder typeBuilder = moduleBuilder.DefineType("Generator");

    // -- 创建构造函数
    ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
    //  - 填充构造函数内需要执行的IL代码
    ILGenerator constructGenerator = constructorBuilder.GetILGenerator();
    //  - 定义一个字符串
    constructGenerator.Emit(OpCodes.Ldstr, "通过Emit构建构造函数中的逻辑代码");
    //  - 调用Console.WriteLine()输出这句话
    constructGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
    //  - 返回
    constructGenerator.Emit(OpCodes.Ret);
    // -- 创建一个方法
    MethodBuilder method = typeBuilder.DefineMethod("Start", MethodAttributes.Public, typeof(void), new Type[] { typeof(string) });
    //  - 声明一个方法参数,名称为 name 
    method.DefineParameter(0, ParameterAttributes.None, "name");
    //  - 编写方法内部的IL代码
    ILGenerator methodGenerator = method.GetILGenerator();
    //  - 将传入的参数 name 打印出来
    methodGenerator.Emit(OpCodes.Ldarg_1);
    methodGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
    methodGenerator.Emit(OpCodes.Ret);
    // -- 创建实例
    Type instance = typeBuilder.CreateType();
    object proxy = Activator.CreateInstance(instance);
// -- 调用 MethodInfo methodInfo
= proxy.GetType().GetMethod("Start"); methodInfo.Invoke(proxy, new string[] { "Hello Elson" }); Console.ReadKey(); }

 三、重点

constructGenerator.Emit(OpCodes.Ldstr, "通过Emit构建构造函数中的逻辑代码");
constructGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
constructGenerator.Emit(OpCodes.Ret);

OpCodes.Ldstr:Pushes a new object reference to a string literal stored in the metadata.

  可以理解为:string a = "Content"

OpCodes.Call:Calls the method indicated by the passed method descriptor.

   可以理解为:以描述的形式调用方法。

         我们原先调用方法的方式是:Console.WriteLine("Content");而使用 Emit 调用方法需要描述该方法:类类型,方法名称,参数类型。

OpCodes.Ret:Returns from the current method, pushing a return value (if present) from the callee's evaluation stack onto the caller's evaluation stack.

   可以理解为:return value

// -- 定义一个方法:方法名称,访问级别,方法特性,返回值类型,参数类型
MethodBuilder method = typeBuilder.DefineMethod("Start", MethodAttributes.Public, typeof(void), new Type[] { typeof(string) }); // -- 声明一个方法参数:参数索引,参数特性,参数名称 method.DefineParameter(0, ParameterAttributes.None, "name"); ILGenerator methodGenerator = method.GetILGenerator(); methodGenerator.Emit(OpCodes.Ldarg_1); methodGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) })); methodGenerator.Emit(OpCodes.Ret);

OpCodes.Ldarg_1:Loads the argument at index 1 onto the evaluation stack.

   获取参数索引位1上的参数,如果不是静态方法,OpCodes.Ldarg_0 获取的是 this,当前对象实例

class Example
{
    public void GetContent(string content)
    {
        //Codes.Ldarg_0 = Example
        var  _this = this;  
        //Codes.Ldarg_1 = content
        var param = content
    }  
}

四、结语

   欢迎大家积极指正,共同学习进步!

谦良恭卑,信诚实至;生活不易,共勉同求。

猜你喜欢

转载自www.cnblogs.com/elsonww/p/12288003.html