ILGenerator.Emit 方法

定义

将指令放到实时 (JIT) 编译器的 Microsoft 中间语言 (MSIL) 流上。

重载

Emit(OpCode, LocalBuilder)

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,后跟给定局部变量的索引。

Emit(OpCode, Type)

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,后跟给定类型的元数据令牌。

Emit(OpCode, String)

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,后跟给定字符串的元数据令牌。

Emit(OpCode, Single)

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, SByte)

将指定的指令和字符参数放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, MethodInfo)

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,后跟给定方法的元数据令牌。

Emit(OpCode, SignatureHelper)

将指定的指令和签名令牌放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, Label[])

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,并留出在完成修正时加上标签所需的空白。

Emit(OpCode, FieldInfo)

将指定字段的指定指令和元数据令牌放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, ConstructorInfo)

将指定构造函数的指定指令和元数据令牌放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, Int64)

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, Int32)

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, Int16)

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, Double)

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode, Byte)

将指定的指令和字符参数放到 Microsoft 中间语言 (MSIL) 指令流上。

Emit(OpCode)

将指定的指令放到指令流上。

Emit(OpCode, Label)

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,并留出在完成修正时加上标签所需的空白。

Emit(OpCode, LocalBuilder)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,后跟给定局部变量的索引。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.Emit.LocalBuilder local);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.Emit.LocalBuilder local);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

local
LocalBuilder

局部变量。

例外

local 参数的父方法与此 ILGenerator 关联的方法不匹配。

localnull

opcode 是单字节指令,并且 local 表示索引大于 Byte.MaxValue 的局部变量。

注解

指令值在枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Type)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,后跟给定类型的元数据令牌。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, Type cls);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, Type cls);

参数

opcode
OpCode

要放到流上的 MSIL 指令。

cls
Type

Type

例外

clsnull

注解

指令值在枚举中 OpCodes 定义。 记录 的位置 cls ,以便在将模块保存到可移植的可执行文件 (PE) 文件时,可以在必要时修补令牌。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, String)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,后跟给定字符串的元数据令牌。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, string str);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, string str);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

str
String

要发出的 String

注解

指令值在枚举中 OpCodes 定义。 如果模块保存到可移植的可执行文件 (PE) 文件,则会记录 的位置 str 以供将来修复。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Single)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, float arg);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, float arg);

参数

opcode
OpCode

要放到流上的 MSIL 指令。

arg
Single

紧接着该指令推到流中的 Single 参数。

注解

指令值在枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, SByte)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

重要

此 API 不符合 CLS。

将指定的指令和字符参数放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
[System.CLSCompliant(false)]
public void Emit (System.Reflection.Emit.OpCode opcode, sbyte arg);

参数

opcode
OpCode

要放到流上的 MSIL 指令。

arg
SByte

紧接着该指令推到流中的字符参数。

属性

注解

指令值在枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, MethodInfo)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,后跟给定方法的元数据令牌。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.MethodInfo meth);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.MethodInfo meth);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

meth
MethodInfo

表示方法的 MethodInfo

例外

methnull

meth 为泛型方法,其 IsGenericMethodDefinition 属性为 false

注解

指令值在枚举中 OpCodes 定义。

记录 的位置 meth ,以便在将模块保存到可移植的可执行文件 (PE) 文件时,可以在必要时修补指令流。

如果 meth 表示泛型方法,则它必须是泛型方法定义。 也就是说,其 MethodInfo.IsGenericMethodDefinition 属性必须为 true

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, SignatureHelper)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令和签名令牌放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.Emit.SignatureHelper signature);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.Emit.SignatureHelper signature);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

signature
SignatureHelper

用于构造签名令牌的帮助程序。

例外

signaturenull

注解

指令值在枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Label[])

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,并留出在完成修正时加上标签所需的空白。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.Emit.Label[] labels);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.Emit.Label[] labels);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

labels
Label[]

从此位置分支到的标签对象的数组。 将使用所有标签。

例外

connull。 此异常是.NET Framework 4 中的新增功能。

示例

下面的代码示例演示了如何使用跳转表创建动态方法。 跳转表是使用 数组 Label生成的。

C#
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;

class DynamicJumpTableDemo
{
   public static Type BuildMyType()
   {
    AppDomain myDomain = Thread.GetDomain();
    AssemblyName myAsmName = new AssemblyName();
    myAsmName.Name = "MyDynamicAssembly";

    AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(
                        myAsmName,
                        AssemblyBuilderAccess.Run);
    ModuleBuilder myModBuilder = myAsmBuilder.DefineDynamicModule(
                        "MyJumpTableDemo");

    TypeBuilder myTypeBuilder = myModBuilder.DefineType("JumpTableDemo",
                            TypeAttributes.Public);
    MethodBuilder myMthdBuilder = myTypeBuilder.DefineMethod("SwitchMe",
                             MethodAttributes.Public |
                             MethodAttributes.Static,
                                             typeof(string),
                                             new Type[] {typeof(int)});

    ILGenerator myIL = myMthdBuilder.GetILGenerator();

    Label defaultCase = myIL.DefineLabel();	
    Label endOfMethod = myIL.DefineLabel();	

    // We are initializing our jump table. Note that the labels
    // will be placed later using the MarkLabel method.

    Label[] jumpTable = new Label[] { myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel() };

    // arg0, the number we passed, is pushed onto the stack.
    // In this case, due to the design of the code sample,
    // the value pushed onto the stack happens to match the
    // index of the label (in IL terms, the index of the offset
    // in the jump table). If this is not the case, such as
    // when switching based on non-integer values, rules for the correspondence
    // between the possible case values and each index of the offsets
    // must be established outside of the ILGenerator.Emit calls,
    // much as a compiler would.

    myIL.Emit(OpCodes.Ldarg_0);
    myIL.Emit(OpCodes.Switch, jumpTable);
    
    // Branch on default case
    myIL.Emit(OpCodes.Br_S, defaultCase);

    // Case arg0 = 0
    myIL.MarkLabel(jumpTable[0]);
    myIL.Emit(OpCodes.Ldstr, "are no bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 1
    myIL.MarkLabel(jumpTable[1]);
    myIL.Emit(OpCodes.Ldstr, "is one banana");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 2
    myIL.MarkLabel(jumpTable[2]);
    myIL.Emit(OpCodes.Ldstr, "are two bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 3
    myIL.MarkLabel(jumpTable[3]);
    myIL.Emit(OpCodes.Ldstr, "are three bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 4
    myIL.MarkLabel(jumpTable[4]);
    myIL.Emit(OpCodes.Ldstr, "are four bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Default case
    myIL.MarkLabel(defaultCase);
    myIL.Emit(OpCodes.Ldstr, "are many bananas");

    myIL.MarkLabel(endOfMethod);
    myIL.Emit(OpCodes.Ret);
    
    return myTypeBuilder.CreateType();
   }

   public static void Main()
   {
    Type myType = BuildMyType();
    
    Console.Write("Enter an integer between 0 and 5: ");
    int theValue = Convert.ToInt32(Console.ReadLine());

    Console.WriteLine("---");
    Object myInstance = Activator.CreateInstance(myType, new object[0]);	
    Console.WriteLine("Yes, there {0} today!", myType.InvokeMember("SwitchMe",
                               BindingFlags.InvokeMethod,
                               null,
                               myInstance,
                               new object[] {theValue}));
   }
}

注解

发出开关表。

指令值在枚举中 OpCodes 定义。

标签是使用 DefineLabel 创建的,并且通过使用 固定 MarkLabel它们在流中的位置。 如果使用单字节指令,则标签可以表示沿流最多 127 个字节的跳转。 opcode 必须表示分支指令。 由于分支是相对指令, label 因此在修复过程中将替换为分支的正确偏移量。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, FieldInfo)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定字段的指定指令和元数据令牌放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.FieldInfo field);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.FieldInfo field);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

field
FieldInfo

表示字段的 FieldInfo

注解

指令值在枚举中 OpCodes 定义。 记录 的位置 field ,以便在将模块保存到可移植的可执行文件 (PE) 文件时,可以在必要时修补指令流。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, ConstructorInfo)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定构造函数的指定指令和元数据令牌放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.ConstructorInfo con);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.ConstructorInfo con);
C#
[System.Runtime.InteropServices.ComVisible(true)]
public virtual void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.ConstructorInfo con);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

con
ConstructorInfo

表示构造函数的 ConstructorInfo

属性

例外

connull。 此异常是.NET Framework 4 中的新增功能。

注解

指令值在 枚举中 OpCodes 定义。

会记录 的位置 con ,以便在将模块保存到可移植的可执行文件 (PE) 文件时,可以在必要时修补指令流。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Int64)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, long arg);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, long arg);

参数

opcode
OpCode

要放到流上的 MSIL 指令。

arg
Int64

紧接着该指令推到流中的数字参数。

注解

指令值在 枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Int32)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, int arg);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, int arg);

参数

opcode
OpCode

要放到流上的 MSIL 指令。

arg
Int32

紧接着该指令推到流中的数字参数。

注解

指令值在 枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Int16)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, short arg);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, short arg);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

arg
Int16

紧接着该指令推到流中的 Int 参数。

注解

指令值在 枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Double)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令和数值参数放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, double arg);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, double arg);

参数

opcode
OpCode

要放到流上的 MSIL 指令。 在 OpCodes 枚举中定义。

arg
Double

紧接着该指令推到流中的数字参数。

注解

指令值在 枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Byte)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令和字符参数放到 Microsoft 中间语言 (MSIL) 指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, byte arg);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, byte arg);

参数

opcode
OpCode

要放到流上的 MSIL 指令。

arg
Byte

紧接着该指令推到流中的字符参数。

注解

指令值在 枚举中 OpCodes 定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令放到指令流上。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode);

参数

opcode
OpCode

要放到流上的 Microsoft 中间语言 (MSIL) 指令。

示例

下面的代码示例演示如何使用 Emit 通过 实例 ILGenerator生成 MSIL 输出。

C#
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;

class DynamicJumpTableDemo
{
   public static Type BuildMyType()
   {
    AppDomain myDomain = Thread.GetDomain();
    AssemblyName myAsmName = new AssemblyName();
    myAsmName.Name = "MyDynamicAssembly";

    AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(
                        myAsmName,
                        AssemblyBuilderAccess.Run);
    ModuleBuilder myModBuilder = myAsmBuilder.DefineDynamicModule(
                        "MyJumpTableDemo");

    TypeBuilder myTypeBuilder = myModBuilder.DefineType("JumpTableDemo",
                            TypeAttributes.Public);
    MethodBuilder myMthdBuilder = myTypeBuilder.DefineMethod("SwitchMe",
                             MethodAttributes.Public |
                             MethodAttributes.Static,
                                             typeof(string),
                                             new Type[] {typeof(int)});

    ILGenerator myIL = myMthdBuilder.GetILGenerator();

    Label defaultCase = myIL.DefineLabel();	
    Label endOfMethod = myIL.DefineLabel();	

    // We are initializing our jump table. Note that the labels
    // will be placed later using the MarkLabel method.

    Label[] jumpTable = new Label[] { myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel() };

    // arg0, the number we passed, is pushed onto the stack.
    // In this case, due to the design of the code sample,
    // the value pushed onto the stack happens to match the
    // index of the label (in IL terms, the index of the offset
    // in the jump table). If this is not the case, such as
    // when switching based on non-integer values, rules for the correspondence
    // between the possible case values and each index of the offsets
    // must be established outside of the ILGenerator.Emit calls,
    // much as a compiler would.

    myIL.Emit(OpCodes.Ldarg_0);
    myIL.Emit(OpCodes.Switch, jumpTable);
    
    // Branch on default case
    myIL.Emit(OpCodes.Br_S, defaultCase);

    // Case arg0 = 0
    myIL.MarkLabel(jumpTable[0]);
    myIL.Emit(OpCodes.Ldstr, "are no bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 1
    myIL.MarkLabel(jumpTable[1]);
    myIL.Emit(OpCodes.Ldstr, "is one banana");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 2
    myIL.MarkLabel(jumpTable[2]);
    myIL.Emit(OpCodes.Ldstr, "are two bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 3
    myIL.MarkLabel(jumpTable[3]);
    myIL.Emit(OpCodes.Ldstr, "are three bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 4
    myIL.MarkLabel(jumpTable[4]);
    myIL.Emit(OpCodes.Ldstr, "are four bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Default case
    myIL.MarkLabel(defaultCase);
    myIL.Emit(OpCodes.Ldstr, "are many bananas");

    myIL.MarkLabel(endOfMethod);
    myIL.Emit(OpCodes.Ret);
    
    return myTypeBuilder.CreateType();
   }

   public static void Main()
   {
    Type myType = BuildMyType();
    
    Console.Write("Enter an integer between 0 and 5: ");
    int theValue = Convert.ToInt32(Console.ReadLine());

    Console.WriteLine("---");
    Object myInstance = Activator.CreateInstance(myType, new object[0]);	
    Console.WriteLine("Yes, there {0} today!", myType.InvokeMember("SwitchMe",
                               BindingFlags.InvokeMethod,
                               null,
                               myInstance,
                               new object[] {theValue}));
   }
}

注解

opcode如果参数需要参数,则调用方必须确保参数长度与声明的参数长度匹配。 否则,结果将是不可预知的。 例如,如果 Emit 指令需要一个 2 字节的操作数,而调用方提供一个 4 字节的操作数,则运行时将向指令流发出另外两个字节。 这些额外的字节将是 Nop 指令。

指令值在 中 OpCodes定义。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1

Emit(OpCode, Label)

Source:
ILGenerator.cs
Source:
ILGenerator.cs
Source:
ILGenerator.cs

将指定的指令放到 Microsoft 中间语言 (MSIL) 流上,并留出在完成修正时加上标签所需的空白。

C#
public virtual void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.Emit.Label label);
C#
public abstract void Emit (System.Reflection.Emit.OpCode opcode, System.Reflection.Emit.Label label);

参数

opcode
OpCode

要发出到流的 MSIL 指令。

label
Label

从此位置分支到的标签。

示例

下面的代码示例演示了如何使用跳转表创建动态方法。 跳转表是使用 数组 Label生成的。

C#
using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;

class DynamicJumpTableDemo
{
   public static Type BuildMyType()
   {
    AppDomain myDomain = Thread.GetDomain();
    AssemblyName myAsmName = new AssemblyName();
    myAsmName.Name = "MyDynamicAssembly";

    AssemblyBuilder myAsmBuilder = myDomain.DefineDynamicAssembly(
                        myAsmName,
                        AssemblyBuilderAccess.Run);
    ModuleBuilder myModBuilder = myAsmBuilder.DefineDynamicModule(
                        "MyJumpTableDemo");

    TypeBuilder myTypeBuilder = myModBuilder.DefineType("JumpTableDemo",
                            TypeAttributes.Public);
    MethodBuilder myMthdBuilder = myTypeBuilder.DefineMethod("SwitchMe",
                             MethodAttributes.Public |
                             MethodAttributes.Static,
                                             typeof(string),
                                             new Type[] {typeof(int)});

    ILGenerator myIL = myMthdBuilder.GetILGenerator();

    Label defaultCase = myIL.DefineLabel();	
    Label endOfMethod = myIL.DefineLabel();	

    // We are initializing our jump table. Note that the labels
    // will be placed later using the MarkLabel method.

    Label[] jumpTable = new Label[] { myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel(),
                      myIL.DefineLabel() };

    // arg0, the number we passed, is pushed onto the stack.
    // In this case, due to the design of the code sample,
    // the value pushed onto the stack happens to match the
    // index of the label (in IL terms, the index of the offset
    // in the jump table). If this is not the case, such as
    // when switching based on non-integer values, rules for the correspondence
    // between the possible case values and each index of the offsets
    // must be established outside of the ILGenerator.Emit calls,
    // much as a compiler would.

    myIL.Emit(OpCodes.Ldarg_0);
    myIL.Emit(OpCodes.Switch, jumpTable);
    
    // Branch on default case
    myIL.Emit(OpCodes.Br_S, defaultCase);

    // Case arg0 = 0
    myIL.MarkLabel(jumpTable[0]);
    myIL.Emit(OpCodes.Ldstr, "are no bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 1
    myIL.MarkLabel(jumpTable[1]);
    myIL.Emit(OpCodes.Ldstr, "is one banana");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 2
    myIL.MarkLabel(jumpTable[2]);
    myIL.Emit(OpCodes.Ldstr, "are two bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 3
    myIL.MarkLabel(jumpTable[3]);
    myIL.Emit(OpCodes.Ldstr, "are three bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Case arg0 = 4
    myIL.MarkLabel(jumpTable[4]);
    myIL.Emit(OpCodes.Ldstr, "are four bananas");
    myIL.Emit(OpCodes.Br_S, endOfMethod);

    // Default case
    myIL.MarkLabel(defaultCase);
    myIL.Emit(OpCodes.Ldstr, "are many bananas");

    myIL.MarkLabel(endOfMethod);
    myIL.Emit(OpCodes.Ret);
    
    return myTypeBuilder.CreateType();
   }

   public static void Main()
   {
    Type myType = BuildMyType();
    
    Console.Write("Enter an integer between 0 and 5: ");
    int theValue = Convert.ToInt32(Console.ReadLine());

    Console.WriteLine("---");
    Object myInstance = Activator.CreateInstance(myType, new object[0]);	
    Console.WriteLine("Yes, there {0} today!", myType.InvokeMember("SwitchMe",
                               BindingFlags.InvokeMethod,
                               null,
                               myInstance,
                               new object[] {theValue}));
   }
}

注解

指令值在 枚举中 OpCodes 定义。

标签是使用 DefineLabel创建的,并且标签在流中的位置是通过使用 固定的 MarkLabel。 如果使用单字节指令,则标签可以表示沿流最多 127 个字节的跳转。 opcode 必须表示分支指令。 由于分支是相对指令, label 因此 在修复过程中,将替换为分支的正确偏移量。

适用于

.NET 9 和其他版本
产品 版本
.NET Core 1.0, Core 1.1, Core 2.0, Core 2.1, Core 2.2, Core 3.0, Core 3.1, 5, 6, 7, 8, 9
.NET Framework 1.1, 2.0, 3.0, 3.5, 4.0, 4.5, 4.5.1, 4.5.2, 4.6, 4.6.1, 4.6.2, 4.7, 4.7.1, 4.7.2, 4.8, 4.8.1
.NET Standard 2.0, 2.1