Free mag vol1 | Page 733

CHAPTER 18  UNDERSTANDING CIL AND THE ROLE OF DYNAMIC ASSEMBLIES Declaring Local Variables in CIL Let’s first check out how to declare a local variable. Assume you wish to build a method in CIL named MyLocalVariables() that takes no arguments and returns void. Within the method, you wish to define three local variables of type System.String, System.Int32, and System.Object. In C#, this member would appear as follows (recall that locally scoped variables do not receive a default value and should be set to an initial state before further use): public static void MyLocalVariables() { string myStr = "CIL code is fun!"; int myInt = 33; object myObj = new object(); } If you were to construct MyLocalVariables() directly in CIL, you could author the following: .method public hidebysig static void MyLocalVariables() cil managed { .maxstack 8 // Define three local variables. .locals init ([0] string myStr, [1] int32 myInt, [2] object myObj) // Load a string onto the virtual execution stack. ldstr "CIL code is fun!" // Pop off current value and store in local variable [0]. stloc.0 // Load a constant of type "i4" // (shorthand for int32) set to the value 33. ldc.i4 33 // Pop off current value and store in local variable [1]. stloc.1 // Create a new object and place on stack. newobj instance void [mscorlib]System.Object::.ctor() // Pop off current value and store in local variable [2]. stloc.2 ret } As you can see, the first step taken to allocate local variables in raw CIL is to make use of the .locals directive, which is paired with the init attribute. Within the scope of the related parentheses, your goal is to associate a given numerical index to each variable (seen here as [0], [1], and [2]). As you can see, each index is identified by its data type and an optional variable name. After the local variables have been defined, you load a value onto the stack (using the various load-centric opcodes) and store the value within the local variable (using the various storage-centric opcodes). 676