信息
您所需的主题如下所示。但此主题未包含在此库中。

OpCodes.Switch 字段

2013/12/13

实现跳转表。

Namespace:  System.Reflection.Emit
程序集:  mscorlib(位于 mscorlib.dll 中)

public static readonly OpCode Switch

下表列出了指令的十六进制和 Microsoft 中间语言 (MSIL) 汇编格式,以及简短的参考摘要:

Format

汇编格式

说明

45 < unsigned int32 > < int32 >... < int32 >

switch (N, t1, t2... tN)

跳转到 N 值之一。

堆栈转换行为依次为:

  1. 将值推送到堆栈上。

  2. 从堆栈中弹出该值并以该值索引的偏移量将执行转移到指令,其中该值小于 N

switch 指令实现跳转表。 该指令的格式是首先为表示目标 N 的数目的 unsigned int32,后跟指定跳转表的 N int32 值。 这些目标被表示为距跟在 switch 指令后的指令的开始处的偏移量(正值或负值)。

switch 指令从堆栈中弹出一个值并将该值(作为无符号整数)与 N 进行比较。 如果值小于 N,则执行被转移到根据值索引的目标,其中目标是从 0 开始编号的(例如,值 0 采用第一个目标,值 1 采用第二个目标,依此类推)。 如果该值大于或等于 N,则继续在下一个指令执行(贯穿)。

如果目标指令有一个或多个前缀代码,则只能将控制转移到其中的第一个前缀。

此指令无法执行进出 trycatchfilterfinally 块的控制转移。 (此类转移受到严格限制并且必须代之以使用退出指令)。

下面的 Emit 方法重载可以使用 switch 操作码: Label[] 参数是表示 32 位偏移量的标签的数组。

  • ILGenerator.Emit(OpCode, Label[])

下面的代码示例演示了如何使用 Switch 操作码通过一个 Label 数组生成一个跳转表。

说明注意:

要运行此示例,请参见生成具有静态 Windows Phone TextBlock 控件的示例


using System;
using System.Reflection;
using System.Reflection.Emit;

class Example
{
   public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      AppDomain myDomain = AppDomain.CurrentDomain;
      AssemblyName myAsmName = new AssemblyName("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();

      // Initialize the jump table. Note that the labels
      // will be placed later using the MarkLabel method. 
      Label[] jumpTable = {myIL.DefineLabel(), 
                           myIL.DefineLabel(), 
                           myIL.DefineLabel(), 
                           myIL.DefineLabel(), 
                           myIL.DefineLabel()};

      // arg0, the method argument, 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);

      Type myType = myTypeBuilder.CreateType();

      int[] testValues = {3, 500, 0};
      object obj = Activator.CreateInstance(myType);
      foreach( int testValue in testValues )
      {
         object result = 
            myType.InvokeMember("SwitchMe", 
                                BindingFlags.InvokeMethod, 
                                Type.DefaultBinder, 
                                obj, 
                                new object[] { testValue });

         outputBlock.Text += String.Format("Yes, there {0} today!\n", result);
      }
   }
}

/* This example produces the following output:

Yes, there are three bananas today!
Yes, there are many bananas today!
Yes, there are no bananas today!
 */


Windows Phone OS

受以下版本支持: 8.0, 7.1

Windows Phone

显示: