Freigeben über


OpCodes.Switch-Feld

Implementiert eine Sprungtabelle.

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

Syntax

'Declaration
Public Shared ReadOnly Switch As OpCode
'Usage
Dim value As OpCode

value = OpCodes.Switch
public static readonly OpCode Switch
public:
static initonly OpCode Switch
public static final OpCode Switch
public static final var Switch : OpCode

Hinweise

In der folgenden Tabelle werden das hexadezimale und das Assemblyformat der MSIL (Microsoft Intermediate Language) jeweils mit einer Kurzreferenz aufgeführt:

Format

Assemblyformat

Beschreibung

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

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

Springt zu einem der N-Werte.

Im Stapel laufen die folgenden Aktionen in der angegebenen Reihenfolge ab:

  1. Ein Wert wird auf dem Stapel abgelegt.

  2. Der Wert wird vom Stapel geholt, und die Ausführung wird an die Anweisung übertragen, die sich am durch den Wert indizierten Offset befindet, wobei der Wert kleiner N ist.

Die switch-Anweisung implementiert eine Sprungtabelle. Die Anweisung ist als unsigned int32 formatiert und stellt die Anzahl der Ziele N gefolgt von N Int32-Werten dar, die die Sprungziele angeben. Diese Ziele werden als (positive oder negative) Offsets vom Anfang der Anweisung dargestellt, die auf diese switch-Anweisung folgt.

Die switch-Anweisung holt einen Wert vom Stapel und vergleicht ihn als ganze Zahl ohne Vorzeichen mit N. Wenn der Wert kleiner als N ist, wird die Ausführung an das durch den Wert indizierte Ziel übertragen, wobei Ziele beginnend mit 0 nummeriert sind (d. h., ein Wert von 0 indiziert das erste Ziel, ein Wert von 1 indiziert das zweite Ziel usw.). Wenn der Wert größer oder gleich N ist, wird die Ausführung mit der nächsten Anweisung fortgesetzt.

Wenn die Zielanweisung Präfixcodes enthält, kann die Steuerung nur an das erste Präfix übertragen werden.

Mit dieser Anweisung kann die Steuerung nicht in einen oder aus einem try-Block, catch-Block, filter-Block und finally-Block übertragen werden. (Übertragungen dieser Art sind strikt eingeschränkt und müssen stattdessen die Abbruchanweisung verwenden.)

Die folgende Überladung der Emit-Methode verwendet den switch-Opcode. Das Label[]-Argument besteht aus einem Array von Sprungmarken, die 32-Bit-Offsets darstellen.

  • ILGenerator.Emit(OpCode, Label[])

Beispiel

Im folgenden Beispiel wird die Verwendung des Switch-Opcodes zum Generieren einer Sprungtabelle unter Verwendung eines Arrays von Label veranschaulicht.

Imports System
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 'Main

End Class 'DynamicJumpTableDemo
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}));  
              
   }

}
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 ) );
}
import System .* ;
import System.Threading .* ;
import System.Reflection .* ;
import System.Reflection.Emit .* ;

class DynamicJumpTableDemo
{
    public static Type BuildMyType()
    {
        AppDomain myDomain = System.Threading.Thread.GetDomain();
        AssemblyName myAsmName = new AssemblyName();
        myAsmName.set_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,
            String.class.ToType(),new Type[] { int.class.ToType() });
        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();
    } //BuildMyType    
   
   public static void main(String[] args)
   {
        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[]{(Int32)(theValue)}));
    } //main
} //DynamicJumpTableDemo

Plattformen

Windows 98, Windows 2000 SP4, Windows Millennium Edition, Windows Server 2003, Windows XP Media Center Edition, Windows XP Professional x64 Edition, Windows XP SP2, Windows XP Starter Edition

.NET Framework unterstützt nicht alle Versionen sämtlicher Plattformen. Eine Liste der unterstützten Versionen finden Sie unter Systemanforderungen.

Versionsinformationen

.NET Framework

Unterstützt in: 2.0, 1.1, 1.0

Siehe auch

Referenz

OpCodes-Klasse
OpCodes-Member
System.Reflection.Emit-Namespace