Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I emit a method with a pre-loaded MethodInfo local variable?

I would like to emit a method that has a variable, which I can do. But, I would like to store in that variable a MethodInfo object, which is a reference to a different (non emitted) method.

I could emit the opcodes to call typeof(someClass).GetMethod(...), but it would be more efficient if I could simply load a token for this MethodInfo and bake it directly into the variable.

So, to rephrase, I'm trying to find out of its possible to emit , let's say a "load object" opcode and pass it an object at emit-time that will be loaded onto the stack at runtime. (OpCodes.Ldobj gave some kind of error when I tried this). Or, am I forced to emit opcodes that will do this at runtime?

like image 798
Jay Sullivan Avatar asked Feb 10 '13 07:02

Jay Sullivan


1 Answers

You can't just load any general object in IL, because there is no way to store it in IL (with the exception of some special types like string). You could work around that using serialization (for types that support it), but I don't think that's what you want. Also, ldobj serves quite a different purpose.

But you can do this for MethodInfo in a way that's very similar to what C# does for the typeof operator. That means:

  1. using the ldtoken instruction to get a RuntimeMethodHandle
  2. calling MethodBase.GetMethodFromHandle() to get a MethodBase
  3. cast it to MethodInfo

The whole code to generate a method that returns the MethodInfo could look like this:

MethodInfo loadedMethod = …;
var getMethodMethod = typeof(MethodBase).GetMethod(
    "GetMethodFromHandle", new[] { typeof(RuntimeMethodHandle) });

var createdMethod = new DynamicMethod(
    "GetMethodInfo", typeof(MethodInfo), Type.EmptyTypes);

var il = createdMethod.GetILGenerator();
il.Emit(OpCodes.Ldtoken, loadedMethod);
il.Emit(OpCodes.Call, getMethodMethod);
il.Emit(OpCodes.Castclass, typeof(MethodInfo));
il.Emit(OpCodes.Ret);

var func = (Func<MethodInfo>)createdMethod.CreateDelegate(typeof(Func<MethodInfo>));
Console.WriteLine(func());
like image 183
svick Avatar answered Nov 14 '22 23:11

svick