情報
要求されたトピックは次のとおりです。しかし、このトピックはこのライブラリには含まれていません。

OpCodes.Switch フィールド

2013/12/12

分岐テーブルを実装します。

Namespace:  System.Reflection.Emit
アセンブリ:  mscorlib (mscorlib.dll 内)

public static readonly OpCode Switch

命令の 16 進数の形式、MSIL (Microsoft Intermediate Language) アセンブリ形式、および簡単な説明の一覧を次の表に示します。

形式

アセンブリ形式

説明

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

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

N 値の 1 つに移動します。

スタックの遷移動作を順番に示すと、次のようになります。

  1. 値がスタックにプッシュされます。

  2. 値がスタックからポップされ、インデックスがこの値であるオフセットにある命令に実行が転送されます。値は N 未満です。

switch 命令は、ジャンプ テーブルを実装します。命令の書式は、ターゲットの数 N を表す unsigned int32 の後ろに、ジャンプ ターゲットを指定する N int32 値が続きます。これらのターゲットは、この switch 命令の次の命令の先頭からのオフセット (正または負) として表されます。

switch 命令は、スタックから値をポップし、符号なし整数として N と比較します。値が N 未満の場合、インデックスがこの値であるターゲットに実行が転送されます。ターゲットの番号は 0 から始まります。たとえば、値が 0 の場合は最初のターゲット、1 の場合は 2 番目のターゲットとなり、以下同様に続きます。値が N 以上の場合は、次の命令で実行が継続されます (フォール スルー)。

ターゲット命令に 1 つ以上のプレフィックス コードがある場合は、最初のプレフィックスだけに制御を転送できます。

この命令では、trycatchfilterfinally の各ブロックの内外への制御の転送は実行できません。このような転送は厳重に制限されており、この命令ではなく leave 命令を使用する必要があります。

switch オペコードを使用できる Emit メソッド オーバーロードを次に示します。Label[] 引数は、32 ビット オフセットを表す Labels の配列です。

  • 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

表示: