ILGenerator::Emit Method (OpCode, array<Label>^)
Puts the specified instruction onto the Microsoft intermediate language (MSIL) stream and leaves space to include a label when fixes are done.
Assembly: mscorlib (in mscorlib.dll)
Parameters
- opcode
-
Type:
System.Reflection.Emit::OpCode
The MSIL instruction to be emitted onto the stream.
- labels
-
Type:
array<System.Reflection.Emit::Label>^
The array of label objects to which to branch from this location. All of the labels will be used.
| Exception | Condition |
|---|---|
| ArgumentNullException | con is null. This exception is new in the .NET Framework 4. |
Emits a switch table.
The instruction values are defined in the OpCodes enumeration.
Labels are created using DefineLabel and their location within the stream is fixed by using MarkLabel. If a single-byte instruction is used, the label can represent a jump of at most 127 bytes along the stream. opcode must represent a branch instruction. Because branches are relative instructions, label will be replaced with the correct offset to branch during the fixup process.
The code sample below illustrates the creation of a dynamic method with a jump table. The jump table is built using an array of 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 ) ); }
Available since 1.1
Portable Class Library
Supported in: portable .NET platforms
Silverlight
Available since 2.0
Windows Phone Silverlight
Available since 7.1