OpCodes.Switch Bidang
Definisi
Penting
Beberapa informasi terkait produk prarilis yang dapat diubah secara signifikan sebelum dirilis. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Mengimplementasikan tabel lompat.
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
Nilai Bidang
Contoh
Sampel kode berikut mengilustrasikan penggunaan Switch
opcode untuk menghasilkan tabel lompat menggunakan array .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
Keterangan
Tabel berikut mencantumkan format rakitan heksadesimal instruksi dan Microsoft Intermediate Language (MSIL), bersama dengan ringkasan referensi singkat:
Format | Format Rakitan | Deskripsi |
---|---|---|
45 <int32 unsigned int32 <>>...<int32 > |
switch (N , t1 , t2 ... tN ) |
Melompat ke salah N satu nilai. |
Perilaku transisi tumpukan, dalam urutan berurutan, adalah:
Nilai didorong ke tumpukan.
Nilai dimunculkan dari tumpukan dan eksekusi ditransfer ke instruksi pada offset yang diindeks oleh nilai, di mana nilainya kurang dari
N
.
Instruksi mengimplementasikan switch
tabel lompat. Format instruksi adalah yang unsigned int32
mewakili jumlah target N
, diikuti oleh N
nilai int32 yang menentukan target lompat. Target ini direpresentasikan sebagai offset (positif atau negatif) dari awal instruksi mengikuti instruksi ini switch
.
Instruksi switch
memunculkan nilai dari tumpukan dan membandingkannya, sebagai bilangan bulat yang tidak ditandatangani, menjadi N
. Jika nilai kurang dari N
, eksekusi ditransfer ke target yang diindeks berdasarkan nilai, di mana target dinomor dari 0 (misalnya, nilai 0 mengambil target pertama, nilai 1 mengambil target kedua, dan sebagainya). Jika nilainya lebih besar dari atau sama dengan N
, eksekusi berlanjut pada instruksi berikutnya (jatuh tempo).
Jika instruksi target memiliki satu atau beberapa kode awalan, kontrol hanya dapat ditransfer ke awalan pertama ini.
Kontrol transfer ke dan keluar dari try
blok , catch
, filter
, dan finally
tidak dapat dilakukan oleh instruksi ini. (Transfer tersebut sangat dibatasi dan harus menggunakan instruksi cuti sebagai gantinya).
Metode berikut Emit kelebihan beban dapat menggunakan switch
opcode. Argumen Label[]
adalah array Label yang mewakili offset 32-bit.