views:

180

answers:

3

I am trying to Emit what I thought would be a simple object array that would result in code similar to the below example

object[] parameters = new object[] { a, b, };

When I write the above code in C# using VS, I get the following IL. As expected this works.

.locals init (
[0] object[] parameters,
[1] object[] CS$0$0000)

However, when I try and Emit IL directly, I only ever get a one index init array. Can someone help tell me where I've gone wrong here?

Here is the Emit code I'm using:

int arraySize = 2;
LocalBuilder paramValues = ilGenerator.DeclareLocal(typeof(object[]));
paramValues.SetLocalSymInfo("parameters");
ilGenerator.Emit(OpCodes.Ldc_I4_S, arraySize);
ilGenerator.Emit(OpCodes.Newarr, typeof(object));
ilGenerator.Emit(OpCodes.Stloc, paramValues);

Here is the resulting IL:

.locals init (
[0] object[] objArray)

The rest of the resulting IL is identical between the two solutions, but for some reason the .locals init is different.

A: 

If you declare only one local (paramValues) then there will be only one local declared. Call DeclareLocal another time if you need a second local. But I don't understand why you'd need this? There is no sense in declaring locals that you don't need.

dtb
Thanks, clearly I've misunderstood what this means. At present this was the only difference between what VS generated and what EMIT generated. I'll have to go back to the drawing board.
JoeGeeky
A: 

The CS$0$0000 variable is here because the compiler didn't optimize variable creation/usages. It uses this automatically created variable for the new object[] { a, b, } part of the code, and then assigns the created object to the object[] parameters variable. This behaviour is mostly beacuse of the stack-based nature of IL. Try running the code in Release mode an see if it gets optimized.

kek444
I tried this in release mode and it didn't change anything. Thanks though...
JoeGeeky
Well, why is it a problem, anyway? The two resulting ILs are equal by effect.
kek444
+1  A: 

The C# compiler generates code like this:

object[] temp = new object[2];
temp[0] = (object)a;
temp[1] = (object)b;
parameters = temp;

The temp variable is the CS$0$0000 you see. I think it does this to ensure that an exception that might be raised while initializing the array doesn't leave a partially initialized array in "parameters". Which could cause unexpected failure when code catches the exception. As written, the named variable is either null or fully initialized. Good idea.

Hans Passant
This makes a lot of sense, and gives me an idea on how to refactor my routines. Thanks for the tip.
JoeGeeky
@Joe: great. Have you figured out the mystery of marking an answer and using the up-vote arrows yet? There's an outline of a V-mark next to each post, you fill it with green by clicking on it.
Hans Passant