Compartir vía


OpCodes.Switch Campo

Definición

Implementa una tabla de saltos.

public: static initonly System::Reflection::Emit::OpCode Switch;
public static readonly System.Reflection.Emit.OpCode Switch;
 staticval mutable Switch : System.Reflection.Emit.OpCode
Public Shared ReadOnly Switch As OpCode 

Valor de campo

Ejemplos

En el Switch ejemplo de código siguiente se muestra el uso del código de operación para generar una tabla de saltos mediante una matriz de Label.

using namespace System;
using namespace System::Threading;
using namespace System::Reflection;
using namespace System::Reflection::Emit;
Type^ BuildMyType()
{
   AppDomain^ myDomain = Thread::GetDomain();
   AssemblyName^ myAsmName = gcnew AssemblyName;
   myAsmName->Name = "MyDynamicAssembly";
   AssemblyBuilder^ myAsmBuilder = myDomain->DefineDynamicAssembly( myAsmName, AssemblyBuilderAccess::Run );
   ModuleBuilder^ myModBuilder = myAsmBuilder->DefineDynamicModule( "MyJumpTableDemo" );
   TypeBuilder^ myTypeBuilder = myModBuilder->DefineType( "JumpTableDemo", TypeAttributes::Public );
   array<Type^>^temp0 = {int::typeid};
   MethodBuilder^ myMthdBuilder = myTypeBuilder->DefineMethod( "SwitchMe", static_cast<MethodAttributes>(MethodAttributes::Public | MethodAttributes::Static), String::typeid, temp0 );
   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.
   array<Label>^jumpTable = gcnew array<Label>(5);
   jumpTable[ 0 ] = myIL->DefineLabel();
   jumpTable[ 1 ] = myIL->DefineLabel();
   jumpTable[ 2 ] = myIL->DefineLabel();
   jumpTable[ 3 ] = myIL->DefineLabel();
   jumpTable[ 4 ] = 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();
}

int 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, gcnew array<Object^>(0) );
   array<Object^>^temp1 = {theValue};
   Console::WriteLine( "Yes, there {0} today!", myType->InvokeMember( "SwitchMe", BindingFlags::InvokeMethod, nullptr, myInstance, temp1 ) );
}
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}));
   }
}

Imports System.Threading
Imports System.Reflection
Imports System.Reflection.Emit

 _

Class DynamicJumpTableDemo
   
   Public Shared Function BuildMyType() As Type

      Dim myDomain As AppDomain = Thread.GetDomain()
      Dim myAsmName As New AssemblyName()
      myAsmName.Name = "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()
      
      ' We are initializing our 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 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()

   End Function 'BuildMyType
    
   
   Public Shared Sub Main()

      Dim myType As Type = BuildMyType()
      
      Console.Write("Enter an integer between 0 and 5: ")
      Dim theValue As Integer = Convert.ToInt32(Console.ReadLine())
      
      Console.WriteLine("---")
      Dim myInstance As [Object] = Activator.CreateInstance(myType, New Object() {})
      Console.WriteLine("Yes, there {0} today!", myType.InvokeMember("SwitchMe", _
                         BindingFlags.InvokeMethod, Nothing, _
                             myInstance, New Object() {theValue}))

   End Sub

End Class

Comentarios

En la tabla siguiente se muestra el formato de ensamblado hexadecimal y del lenguaje intermedio de Microsoft (MSIL), junto con un breve resumen de referencia:

Formato Formato de ensamblado Descripción
45 <int32unsigned int32<>>...<int32> switch (N, t1, t2... tN) Salta a uno de N los valores.

El comportamiento transitorio de la pila, en orden secuencial, es:

  1. Un valor se inserta en la pila.

  2. El valor se extrae de la pila y la ejecución se transfiere a la instrucción en el desplazamiento indexado por el valor, donde el valor es menor que N.

La switch instrucción implementa una tabla de saltos. El formato de la instrucción es un unsigned int32 que representa el número de destinos N, seguido de N valores int32 que especifican destinos de salto. Estos destinos se representan como desplazamientos (positivos o negativos) desde el principio de la instrucción que sigue a esta switch instrucción.

La switch instrucción extrae un valor de la pila y lo compara, como un entero sin signo, con N. Si el valor es menor que N, la ejecución se transfiere al destino indexado por valor, donde los destinos se numeran de 0 (por ejemplo, un valor de 0 toma el primer destino, un valor de 1 toma el segundo destino, etc.). Si el valor es mayor o igual que N, la ejecución continúa en la siguiente instrucción (se pasa).

Si la instrucción de destino tiene uno o varios códigos de prefijo, el control solo se puede transferir al primero de estos prefijos.

Esta instrucción no puede realizar las transferencias de controles dentro y fuera de try, catch, filtery finally . (Estas transferencias están severamente restringidas y deben usar la instrucción leave en su lugar).

La sobrecarga del método siguiente Emit puede usar el switch código de operación. El Label[] argumento es una matriz de etiquetas que representa desplazamientos de 32 bits.

Se aplica a