In the newest version of the .NET framework, version 4.5, the MethodBuilder class has a method called SetMethodBody
that I believe is exactly what I'm looking at as an alternative to using ILGenerator (which is annoying and limited in odd ways). The documentation can be found here, although since .NET 4.5 is not out yet, it is not fully documented. I can supply all but two of the arguments, but the rest I will need help with.
The first that I don't understand is byte[] localSignature
, the third argument. MSDN states that it is "An array of bytes that contain the serialized local variable structure. Specify null if the method has no local variables." The trouble is, that's all it says, and I can't find out the format of a "serialized local variable signature." I have tried looking in the ECMA-335 spec, but all I have found is how to specify the local variables in unassembled CIL. If anybody could help me figure this out, it would be much appreciated.
Also, the last argument is IEnumerable<int> tokenFixups
, which is "A collection of values that represent offsets in il, each of which specifies the beginning of a token that may be modified. Specify null if the method has no tokens that have to be modified.". I suspect that I won't need to use these, but I'd like to know what they are anyway.
Thanks, Brandon
The real answer to my question was posted as a comment, instead of an answer, so in case anybody else ever has this question... here's the posted answer:
You'll need the SignatureHelper class. Fixups are only for compilers that translate native code to IL, like C++/CLI. – Hans Passant Mar 10 at 13:02
So... in order to get the byte array for the local signatures, you can execute this code:
var sig = SignatureHelper.GetLocalVarSigHelper(this.module);
sig.AddArgument(typeof(int)); //Local #0 is of type int
...
sig.AddArgument(typeof(string)); //Local #n is of type string
var sigArray = sig.GetSignature();
And in order to set the method body on the MethodBuilder, you call
MethodBuilder.SetMethodBody(il, maxStack, sigArray, handlers, fixups);
...where il is a byte[]
with valid IL instructions (see this page), maxStack is an integer with the number of spots to reserve on the stack for the method, handlers is an System.Reflection.Emit.ExceptionHandler[]
, and fixups is a int[]
array that can be ignored (with one exception, see below.)
One thing that I disagree with in Hans Passant's comment is that fixups are not only for compilers that translate native code into IL. I discovered when working on this that if you try to emit a call to a MethodBuilder
method, it emits the wrong instruction. Looking at ILGenerator in .NET reflector, I found out that they emit a fixup each time they emit a method call. Adding a fixup for each method call indeed fixed this problem. There may be other places where you need to emit a fixup for it to work correctly, but I haven't looked into it much.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With