OpCodes.Switch Campo
Definizione
Importante
Alcune informazioni sono relative alla release non definitiva del prodotto, che potrebbe subire modifiche significative prima della release definitiva. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.
Implementa una tabella di collegamento.
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
Valore del campo
Esempio
Nell'esempio di codice seguente viene illustrato l'uso del Switch
codice operativo per generare una tabella di salto usando una matrice di 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
Commenti
La tabella seguente elenca il formato di assembly Esadecimale e MSIL (Microsoft Intermediate Language), insieme a un breve riepilogo dei riferimenti:
Formato | Formato assembly | Descrizione |
---|---|---|
45 <int32 unsigned int32 <>>...<int32 > |
switch (N , t1 , t2 ... tN ) |
Passa a uno dei N valori. |
Il comportamento di transizione dello stack, in ordine sequenziale, è:
Viene eseguito il push di un valore nello stack.
Il valore viene estratto dallo stack e l'esecuzione viene trasferita all'istruzione in corrispondenza dell'offset indicizzato dal valore, dove il valore è minore di
N
.
L'istruzione switch
implementa una tabella di salto. Il formato dell'istruzione è un oggetto che unsigned int32
rappresenta il numero di destinazioni N
, seguito da N
valori int32 che specificano le destinazioni di salto. Queste destinazioni sono rappresentate come offset (positivi o negativi) dall'inizio dell'istruzione che segue questa switch
istruzione.
L'istruzione switch
popa un valore dallo stack e lo confronta, come intero senza segno, con N
. Se il valore è minore di N
, l'esecuzione viene trasferita alla destinazione indicizzata per valore, dove le destinazioni sono numerate da 0 (ad esempio, un valore pari a 0 accetta la prima destinazione, un valore pari a 1 accetta la seconda destinazione e così via). Se il valore è maggiore o uguale a N
, l'esecuzione continua all'istruzione successiva (fall through).
Se l'istruzione di destinazione ha uno o più codici di prefisso, il controllo può essere trasferito solo al primo di questi prefissi.
I trasferimenti di controlli all'esterno di try
, catch
, filter
e finally
non possono essere eseguiti da questa istruzione. Tali trasferimenti sono fortemente limitati e devono usare invece l'istruzione di uscita.
L'overload del metodo seguente Emit può usare il switch
codice operativo. L'argomento Label[]
è una matrice di etichette che rappresenta gli offset a 32 bit.