I have a LocalBuilder
, which is essentially an array. I can use it in IL just fine, and I can load it's length using OpCodes.Ldlen
. I was just wondering, if there is any way to get the length from top of stack to some actual variable. I am looking for something like
int lengthVariable = 0;
IL.Emit(OpCodes.Ldloc, arr);
IL.Emit(OpCodes.Ldlen);
IL.Emit(??????, lengthVariable);
I want to get this variable so that I can run a loop based on array's length. I know I can create a loop in IL, but I thought it would be a lot more convenient if this was possible.
Edit: What I'm trying to do over here is
The problem with this is that I now have to call the external method twice. I was hoping that I could get the length from IL array so that I can loop over it directly, without calling the external method twice. I know I can write a for loop in IL, but I was kind of avoiding writing branching statements of IL.
You can't populate your local lengthVariable
like that - it runs in a completely separate scope / stack-frame. However, you could change your method (DynamicMethod
or MethodBuilder
) to return it, then create a delegate to your new method as a Func<int>
, and invoke it.
Then your last line would be IL.Emit(Opcodes.Ret);
, to return the single value on the local stack. Alternatively, you could store the value into an instance or static field, with Opcodes.Stfld
or Opcodes.Stsfld
.
Following discussion in comments, it seems that the remark
I know I can write a for loop in IL, but I was kind of avoiding writing branching statements of IL.
in the question may be surmountable; foreach
isn't really all that tricky - the final IL you're after is obtainable by decompiling existing code, which leaves the only really tricky bit the handling of labels for the actual branch targets - but that just means calling .DefineLabel()
to declare them - you can use them as targets before you know where they'll be jumping to - and .MarkLabel()
to position them (once only). It isn't quite direct IL (it uses an abstraction layer), but you can see this approach being used here - in particular, note that it uses DefineLabel()
ahead of time, and marks the destinations later at MarkLabel
.