Generate DynamicMethod from MethodInfo - c#

I was going over a Joel Pobar's Dodge Common Performance Pitfalls to Craft Speedy Applications article on Reflection and I was looking at a particular piece of code that isn't compiling (slightly modified to narrow down to the specific error, because his example had more errors):
MethodInfo writeLine = typeof(Console).GetMethod("WriteLine");
RuntimeMethodHandle myMethodHandle = writeLine.MethodHandle;
DynamicMethod dm = new DynamicMethod(
"HelloWorld", // name of the method
typeof(void), // return type of the method
new Type[]{}, // argument types for the method
false); // skip JIT visibility checks
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Hello, world");
il.Emit(OpCodes.Call, myMethodHandle); // <-- 2 errors here
il.Emit(OpCodes.Ret);
The errors are:
Program.cs(350,13): error CS1502: The best overloaded method match for 'System.Reflection.Emit.ILGenerator.Emit(System.Reflection.Emit.OpCode, byte)' has some invalid arguments
Program.cs(350,35): error CS1503: Argument '2': cannot convert from 'System.RuntimeMethodHandle' to 'byte'
The ILGenerator can Emit with a MethodInfo, but it doesn't seem to support MethodHandle... does anybody know how to get this sample to work?

Like so?
MethodInfo writeLine = typeof(Console).GetMethod("WriteLine", new Type[] {typeof(string)});
RuntimeMethodHandle myMethodHandle = writeLine.MethodHandle;
DynamicMethod dm = new DynamicMethod(
"HelloWorld", // name of the method
typeof(void), // return type of the method
new Type[] { }, // argument types for the method
false); // skip JIT visibility checks
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldstr, "Hello, world");
il.EmitCall(OpCodes.Call, writeLine, null);
il.Emit(OpCodes.Ret);
// test it
Action act = (Action)dm.CreateDelegate(typeof(Action));
act();
Changes:
I used a tweaked GetMethod to find the (string) overload (otherwise it is an ambiguous match)
use the MethodInfo, not the handle (since that is what ILGenerator wants)
use EmitCall (the other might have worked too, but I know this way works)

Through this library on Nuget.org:
ClassWrapper
It creates wrappers for types that internally uses dynamically generated methods. So no reflection used (only into the ClassWrapperDescriptor.Load method to generate the dynamic expressions)
Given, e.g. e class named SampleClass
//Create the class wrapper descriptor, this can be cached and reused!
var classWrapperDescriptor = new ClassWrapperDescriptor(typeof(SampleClass));
//Initialize the descriptor
classWrapperDescriptor.Load();
//Create the instance of our object
object instance = new SampleClass();
//Create an instance of the wrapper
var classWrapper = classWrapperDescriptor.CreateWrapper(instance);
//Set a property
classWrapper.Set("StringProperty","test");
//Get a property
var stringPropertyValue = classWrapper.Get<string>("StringProperty");
//Invoke a method without return statement
classWrapper.Invoke("ParamMethod", "paramValue");
//Invoke a method witho return statement
var result = classWrapper.Invoke<int>("ReturnMethod", "paramValue");
Any feedback on this library is really appreciated!

Related

C# - Reflection.Emit: Return reference to a local variable

I want to make a DynamicMethod which in turn behave like the following for example:
AnyClass myClass = new AnyClass();
Func<AnyClass> myFunc = () => myClass;
I know that when I want to make it work with an int instead of AnyClass I have to use the following snippet to return every time the number 12:
// Define method
DynamicMethod method = new DynamicMethod(
"Name",
typeof(int),
new Type[] { });
// Define method body
ILGenerator il = method.GetILGenerator();
il.Emit(OpCodes.Ldc_I4, 12);
il.Emit(OpCodes.Ret);
But now I ask myself how to do it with a not build-in class.
Edit:
At the end I want to get a reference from a local variable when I call the DynamicMethod. Look at the following snippet to better understand what I wanted to archieve. Here I want a func which returns on every call the variable I passed to the function which creates the func.
Func<AnyClass> GetMethodWithAFunc(AnyClass myClass) {
Func<AnyClass> myFunc = () => myClass;
return myFunc;
}
The generated IL Code for the snippet can be found on SharpLab. Unfortunately we have to provide a context where the data to return in the DynamicMethod could be saved. Finally I suggest a static cache and to use converting and unboxing when returning the values.

Method created during runtime changes the parameter order of another method call depending on how it is run

I implement interfaces during runtime using Reflection.Emit and create their defined methods.
Example definition of a method in the interface:
IFoo DoSomething(IBar bar, string name);
To create the methods I do the following:
var args = methodInfo.GetParameters();
MethodBuilder methodBuilder = typeBuilder.DefineMethod(methodInfo.Name, MethodAttributes.Public | MethodAttributes.Virtual,
methodInfo.ReturnType, (from arg in args select arg.ParameterType).ToArray());
typeBuilder.DefineMethodOverride(methodBuilder, methodInfo);
var generator = methodBuilder.GetILGenerator();
generator.Emit(OpCodes.Ldarg_0);
generator.Emit(OpCodes.Ldfld, fieldBuilder);
generator.Emit(OpCodes.Ldtoken, methodInfo.ReturnType);
if (args.Any())
{
generator.Emit(OpCodes.Ldc_I4_S, args.Length);
generator.Emit(OpCodes.Newarr, typeof(object));
for (int i = 0; i < args.Length; i++)
{
generator.Emit(OpCodes.Dup);
generator.Emit(OpCodes.Ldc_I4_S, i);
generator.Emit(OpCodes.Ldarg_S, i + 1);
generator.Emit(OpCodes.Stelem_Ref);
}
}
else
{
generator.Emit(OpCodes.Ldc_I4_0);
}
generator.EmitCall(OpCodes.Callvirt, typeof(ISomeType).GetMethod(nameof(ISomeType.Test), new[] {typeof(Type), typeof(object[])}), null);
generator.Emit(OpCodes.Ret);
This generates me for example my DoSomething(IBar bar, string name) method of the interface.
All generated methods call the method Test() of ISomeType.
This is the method Test():
public object Test(Type type, object[] arguments)
{
//do something
}
When I run my application and call the DoSomething() method, the parameters are passed the wrong way (object[] first and Type second) to Test(), which obviously leads to an exception.
But when I run a unit test and call the DoSomething() method, the parameters are passed correctly (Type first and object[] second) to Test().
Why is there a difference in which order the parameters are passed to the Test() method depending on how it is run?
So with a lot of help of Marc Gravell in the comments I found out what to do to get this problem fixed.
First of all I had an error in the way I created my methods.
The case when a method has no arguments has to be changed from
generator.Emit(OpCodes.Ldc_I4_0);
that pushes just a 0 as Int32 onto the stack, to
MethodInfo emptyArray = typeof(Array).GetMethod(nameof(Array.Empty))?.MakeGenericMethod(typeof(object));
generator.EmitCall(OpCodes.Call, emptyArray, null);
which really pushes an empty array to the stack that will get passed as an argument to the Test() function.
To fix the problem with the wrong parameter order there are two possible solutions in my specific case:
(1) More changes to the generated IL code:
Really push the return type of the method as a Type and not a RuntimeTypeHandle:
generator.Emit(OpCodes.Ldtoken, methodInfo.ReturnType);
MethodInfo getTypeFromHandle = typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle));
generator.EmitCall(OpCodes.Call, getTypeFromHandle, null);
Cast the return type of Test() to the wanted return type of the method before returning:
generator.EmitCall(OpCodes.Callvirt, typeof(ISomeType).GetMethod(nameof(ISomeType.Test), new[] {typeof(Type), typeof(object[])}), null);
generator.Emit(OpCodes.Castclass, methodInfo.ReturnType);
generator.Emit(OpCodes.Ret);
(2) Convert Test() method to a generic method:
In case you have parameters as a Type you can convert your method to a generic method:
public T Test<T>(object[] arguments)
{
//do something
}
If you decide to do so, you will have to change some of the IL code generation as well:
Don't push return type of the method to the stack:
Remove this line:
generator.Emit(OpCodes.Ldtoken, methodInfo.ReturnType);
Change the call of Test():
MethodInfo test = typeof(ISomeType).GetMethod(nameof(ISomeType.Test), new[] { typeof(object[]) }).MakeGenericMethod(methodInfo.ReturnType);
generator.EmitCall(OpCodes.Callvirt, test, null);
generator.Emit(OpCodes.Ret);
You also don't have to cast the return value in this case because your method Test() already returns the correct type with T.
With any of those two solutions the Test() method gets call with the correct parameter order regardless of how it is called (application or unit test).
Another tip of Marc Gravell was to use Sigil to get clear error messages when your generated IL code is invalid. And no matter which of the two solutions above you are choosing I can only recommend to do so.

How to use Mono.Cecil to parse IL Instructions from byte array

I am dynamically compiling source code using CodeDOM,
now i want to work with the generated IL code of a particular method using Cecil, CodeDOM provides me with the IL code of the method as a byte array, is there any way to create a MethodBody, (or just an array of Mono.Cecil.Cil.Instruction) from that bytecode without saving the assembly and going from there?
There is functionality in Cecil that parses binary IL. It's in the class CodeReader in the Mono.Cecil.Cil namespace.
The method ReadCode does more or less what you want. But the class is set up in a way that you can't just pass in a byte[]. In general, you need to resolve metadata tokens, e.g. for method calls. CodeReader requires a MetadataReader via constructor to do this and MetadataReader in turn requires a ModuleDefinition.
There is an alternative if you don't use Cecil. Use SDILReader:
// get the method that you want to extract the IL from
MethodInfo methodInfo = typeof(Foo).GetMethod("Bar", BindingFlags.Static | BindingFlags.NonPublic);
Globals.LoadOpCodes();
// doesn't work on DynamicMethod
MethodBodyReader reader = new MethodBodyReader(methodInfo);
List<ILInstruction> instructions = reader.instructions;
string code = reader.GetBodyCode();
Another alternative is ILReader from ILVisualizer 2010 Solution.
DynamicMethod dynamicMethod = new DynamicMethod("HelloWorld", typeof(void), new Type[] { }, typeof(Program), false);
ILGenerator ilGenerator = dynamicMethod.GetILGenerator();
ilGenerator.Emit(OpCodes.Ldstr, "hello, world");
ilGenerator.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
ilGenerator.Emit(OpCodes.Ret);
MethodBodyInfo methodBodyInfo = MethodBodyInfo.Create(dynamicMethod);
string ilCode = string.Join(Environment.NewLine, methodBodyInfo.Instructions);
// get the method that you want to extract the IL from
MethodInfo methodInfo = typeof(Foo).GetMethod("Bar", BindingFlags.Static | BindingFlags.NonPublic);
MethodBodyInfo methodBodyInfo2 = MethodBodyInfo.Create(methodInfo);
string ilCode2 = string.Join(Environment.NewLine, methodBodyInfo2.Instructions);

Why is a TypeBuilder generated generic methodinfo not a generic method?

I have some code that uses a MethodInfo of a generic method found on a generated type. To avoid some reflection, I have the code use the
ldtoken Method
ldtoken Type
call GetMethodFromHandle(RuntimeMethodHandle,RunTimeTypeHandle)
Pattern to generate the MethodInfos at compile time.
However, if the methodInfo belongs to a generic type and itself is a generic method things get screwy.
Here is some code that simply generates a GM that emits an open version of its methodInfo.
If I call it to retrieve the method than try to close it over a specific type I get a perplexing exception::
System.Reflection.MethodInfo GM[M]() is not a GenericMethodDefinition. MakeGenericMethod may only be called on a method for which MethodBase.IsGenericMethodDefinition is true.
Here is the relevant code::
var aBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("Test"), AssemblyBuilderAccess.RunAndSave);
var mBuilder = aBuilder.DefineDynamicModule(aBuilder.GetName().Name, true);
var typeBuilder = mBuilder.DefineType("NameSpace.Generic`1",TypeAttributes.AutoClass | TypeAttributes.Sealed | TypeAttributes.Public,typeof(object));
var TypeGenerics = typeBuilder.DefineGenericParameters(new[] { "T" });
var methodBuilder = typeBuilder.DefineMethod("GM", MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.HideBySig);
var methodGenerics = methodBuilder.DefineGenericParameters(new[] { "M" });
methodBuilder.SetSignature(typeof(MethodInfo), null, null, Type.EmptyTypes, null, null);
var ilgenerator = methodBuilder.GetILGenerator();
var typeBuilderClosedOverT = typeBuilder.MakeGenericType(TypeGenerics);
ilgenerator.Emit(OpCodes.Ldtoken, methodBuilder);
ilgenerator.Emit(OpCodes.Ldtoken, typeBuilderClosedOverT);
ilgenerator.Emit(OpCodes.Call,
typeof(MethodBase).GetMethod(
"GetMethodFromHandle",
BindingFlags.Public | BindingFlags.Static,
null,
new[] { typeof(RuntimeMethodHandle), typeof(RuntimeTypeHandle) },
null
)
);
ilgenerator.Emit(OpCodes.Castclass,typeof(MethodInfo));
ilgenerator.Emit(OpCodes.Ret);
var bakedType = typeBuilder.CreateType();
var methodInfo = bakedType.MakeGenericType(typeof(int)).GetMethod("GM").MakeGenericMethod(typeof(bool)).Invoke(null, null) as MethodInfo;
var methodInfoClosedOverBool = methodInfo.MakeGenericMethod(typeof(bool));
It seems the only time my code screws up is if it's a genericmethod on a non-generic type. If the code is rewritten so that its about a normal method on a normal type, or a generic method on a normal type, or a normal method on a generic type it all works. It's only the combination of both that causes errors. Am I doing something wrong?
I submitted a bug about this issue:
https://connect.microsoft.com/VisualStudio/feedback/details/775989/clr-cannot-emit-a-token-for-an-open-generic-method-on-a-generic-type
Looks like a CLR issue to me, because the same thing happens if you write the IL by hand and use ilasm. That is, given a generic class G and a nongeneric class N, each with a generic method M, then trying to get the generic method definition from the non-generic class works:
ldtoken method void class N::M<[1]>()
ldtoken class N<!T>
call class [mscorlib]System.Reflection.MethodBase [mscorlib]
System.Reflection.MethodBase::GetMethodFromHandle(
valuetype [mscorlib]System.RuntimeMethodHandle,
valuetype [mscorlib]System.RuntimeTypeHandle)
castclass [mscorlib]System.Reflection.MethodInfo
ret
but the MethodInfo returned from the generic class is not a generic method definition (but it almost is; it's D.MakeGenericMethod(D.GetGenericArguments()) where D is the method definition you want):
ldtoken method void class G`1<!T>::M<[1]>()
ldtoken class G`1<!T>
call class [mscorlib]System.Reflection.MethodBase [mscorlib]
System.Reflection.MethodBase::GetMethodFromHandle(
valuetype [mscorlib]System.RuntimeMethodHandle,
valuetype [mscorlib]System.RuntimeTypeHandle)
castclass [mscorlib]System.Reflection.MethodInfo
ret
The problem lies within the ldtoken method instruction because, due to the inability of IL to express generic method definitions, the CLR loads the wrong method. The instruction is decompiled by ildasm to this:
ldtoken method class [mscorlib]System.Reflection.MethodInfo class NameSpace.Generic`1<!T>::GM<[1]>()
Which isn't even valid IL. The CLR then messes up the instruction and instead loads a generic method instantiation from it's own generic parameters.
var methodInfoClosedOverBool = (methodInfo.IsGenericMethodDefinition ? methodInfo : methodInfo.GetGenericMethodDefinition()).MakeGenericMethod(typeof(bool));
For more tests, I've made a shorter code showing the same issue:
DynamicMethod dyn = new DynamicMethod("", typeof(RuntimeMethodHandle), null);
var il = dyn.GetILGenerator();
il.Emit(OpCodes.Ldtoken, typeof(GenClass<string>).GetMethod("GenMethod"));
il.Emit(OpCodes.Ret);
var handle = (RuntimeMethodHandle)dyn.Invoke(null, null);
var m = MethodBase.GetMethodFromHandle(handle, typeof(GenClass<int>).TypeHandle);
GetMethodFromHandle (which should also only require the method handle, not the declaring type) just sets the declaring type (notice <int> or <string> doesn't matter) and doesn't do anything wrong.

Using reflection to find DynamicMethods

I'd like to somehow find all DynamicMethods in my current context, consider that I have the following method and delegate:
public delegate double DivideInvoker(int a, int b);
public DivideInvoker CreateInvoker()
{
Type[] methodArguments = {
typeof(int),
typeof(int)
};
DynamicMethod division = new DynamicMethod(
"Division",
typeof(double),
methodArguments,
typeof(MyMethodCreator));
ILGenerator il = division.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldarg_1);
il.Emit(OpCodes.Div);
il.Emit(OpCodes.Ret);
var divideIt = (DivideInvoker)division.CreateDelegate(typeof(DivideInvoker));
return divideIt;
}
If I were to do: var divideIt = CreateInvoker();, can I somehow use reflection to find the dynamic method method?
According to MSDN the above dynamic method will be static and once it's not used anymore it will be disposed by the GC, I am just using this to play around with reflection.
I've tried getting all types in the executing assembly and listing all the methods on them, but I can't find anything on the DynamicMethod.
Any ideas?
DivideInvoker invoker = CreateInvoker();
MethodInfo method = invoker.Method;
// method will contain the MethodInfo of the Division dynamic method
// so you could use reflection on it

Categories

Resources