Partager via


OpCodes.Switch Field

Microsoft Silverlight will reach end of support after October 2021. Learn more.

Implements a jump table.

Namespace:  System.Reflection.Emit
Assembly:  mscorlib (in mscorlib.dll)

Syntax

'Declaration
Public Shared ReadOnly Switch As OpCode
public static readonly OpCode Switch

Remarks

The following table lists the instruction's hexadecimal and Microsoft intermediate language (MSIL) assembly format, along with a brief reference summary:

Format

Assembly Format

Description

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

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

Jumps to one of N values.

The stack transitional behavior, in sequential order, is:

  1. A value is pushed onto the stack.

  2. The value is popped off the stack and execution is transferred to the instruction at the offset indexed by the value, where the value is less than N.

The switch instruction implements a jump table. The format of the instruction is an unsigned int32 representing the number of targets N, followed by N int32 values specifying jump targets. These targets are represented as offsets (positive or negative) from the beginning of the instruction following this switch instruction.

The switch instruction pops a value off the stack and compares it, as an unsigned integer, to N. If value is less than N, execution is transferred to the target indexed by value, where targets are numbered from 0 (for example, a value of 0 takes the first target, a value of 1 takes the second target, and so on). If the value is greater than or equal to N, execution continues at the next instruction (fall through).

If the target instruction has one or more prefix codes, control can only be transferred to the first of these prefixes.

Control transfers into and out of try, catch, filter, and finally blocks cannot be performed by this instruction. (Such transfers are severely restricted and must use the leave instruction instead).

The following Emit method overload can use the switch opcode. The Label[] argument is an array of Labels representing 32-bit offsets.

  • ILGenerator.Emit(OpCode, Label[])

Examples

The following code sample illustrates the use of the Switch opcode to generate a jump table using an array of Label.

Imports System.Reflection
Imports System.Reflection.Emit

Class Example

   Public Shared Sub Demo(ByVal outputBlock As System.Windows.Controls.TextBlock)

      Dim myDomain As AppDomain = AppDomain.CurrentDomain
      Dim myAsmName As New AssemblyName("MyDynamicAssembly")

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

      Dim myTypeBuilder As TypeBuilder = myModBuilder.DefineType("JumpTableDemo", _
                                                         TypeAttributes.Public)
      Dim myMthdBuilder As MethodBuilder = _
         myTypeBuilder.DefineMethod("SwitchMe", _
                              MethodAttributes.Public Or MethodAttributes.Static, _
                              GetType(String), New Type() {GetType(Integer)})

      Dim myIL As ILGenerator = myMthdBuilder.GetILGenerator()

      Dim defaultCase As Label = myIL.DefineLabel()
      Dim endOfMethod As Label = myIL.DefineLabel()

      ' Initialize the jump table. Note that the labels
      ' will be placed later using the MarkLabel method. 
      Dim jumpTable() As Label = { 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)

      Dim myType As Type = myTypeBuilder.CreateType()

      Dim testValues() As Integer = { 3, 500, 0 }
      Dim obj As Object = Activator.CreateInstance(myType)
      For Each testValue As Integer In testValues

         Dim result As Object = _
            myType.InvokeMember("SwitchMe", _
                                BindingFlags.InvokeMethod, _
                                Type.DefaultBinder, _
                                obj, _
                                New Object() { testValue })

         outputBlock.Text &= String.Format("Yes, there {0} today!", result) & vbLf
      Next

   End Sub 
End Class 

' This example produces the following output:
'
'Yes, there are three bananas today!
'Yes, there are many bananas today!
'Yes, there are no bananas today!
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!
 */

Version Information

Silverlight

Supported in: 5, 4, 3

Silverlight for Windows Phone

Supported in: Windows Phone OS 7.1

Platforms

For a list of the operating systems and browsers that are supported by Silverlight, see Supported Operating Systems and Browsers.