AceInfinity
Emeritus, Contributor
So I wanted to see how some LINQ looked in MSIL. I took this quick and simple query which returns an IEnumerable<Int32>:
And I got this:
What's happening in the above, is the load string (ldstr) opcode is being called for our initial string value to get loaded onto the stack, so that we can make calls to the later methods we want to use. (Everything should be loaded onto the stack before our methods are to perform any kind of instructions on them.) Next, a late bound call is made to the System.String.ToCharArray() function on our loaded string popped from the stack,
Then we load our function which takes the char.ToString and calls the Int32.Parse method on it, since the parse method is expected to succeed, we pop the result off the top of the stack, and place it into our new variable at index 0, and proceed to load the modified local variable at index 0 onto the stack before calling to return.
When we do this, as you can see we embed a System.Func<> delegate, where a char is converted to a 32 bit signed integer output.
After all that is done, we call upon System.Linq.Enumerable.Select which casts the elements of the sequence on the stack to an IEnumerable object.
Code:
from char c in "012345678".ToCharArray()
select Int32.Parse(c.ToString())
And I got this:
Code:
IL_0001: ldstr "012345678"
IL_0006: callvirt System.String.ToCharArray
IL_000B: call System.Linq.Enumerable.Cast
IL_0010: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0015: brtrue.s IL_002A
IL_0017: ldnull
IL_0018: ldftn b__0
IL_001E: newobj System.Func..ctor
IL_0023: stsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_0028: br.s IL_002A
IL_002A: ldsfld UserQuery.CS$<>9__CachedAnonymousMethodDelegate1
IL_002F: call System.Linq.Enumerable.Select
b__0:
IL_0000: ldarga.s 00
IL_0002: call System.Char.ToString
IL_0007: call System.Int32.Parse
IL_000C: stloc.0
IL_000D: br.s IL_000F
IL_000F: ldloc.0
IL_0010: ret
What's happening in the above, is the load string (ldstr) opcode is being called for our initial string value to get loaded onto the stack, so that we can make calls to the later methods we want to use. (Everything should be loaded onto the stack before our methods are to perform any kind of instructions on them.) Next, a late bound call is made to the System.String.ToCharArray() function on our loaded string popped from the stack,
Then we load our function which takes the char.ToString and calls the Int32.Parse method on it, since the parse method is expected to succeed, we pop the result off the top of the stack, and place it into our new variable at index 0, and proceed to load the modified local variable at index 0 onto the stack before calling to return.
When we do this, as you can see we embed a System.Func<> delegate, where a char is converted to a 32 bit signed integer output.
After all that is done, we call upon System.Linq.Enumerable.Select which casts the elements of the sequence on the stack to an IEnumerable object.