Using reflection to find DynamicMethods - c#

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

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.

How can I emit a dynamic method returning a ref?

I'm navigating the ins and outs of ref returns, and am having trouble emitting a dynamic method which returns by ref.
Handcrafted lambdas and existing methods work as expected:
class Widget
{
public int Length;
}
delegate ref int WidgetMeasurer(Widget w);
WidgetMeasurer GetMeasurerA()
{
return w => ref w.Length;
}
static ref int MeasureWidget(Widget w) => ref w.Length;
WidgetMeasurer GetMeasurerB()
{
return MeasureWidget;
}
But emitting a dynamic method fails. Note: I'm using Sigil here. Apologies, I'm less familiar with System.Reflection.Emit.
WidgetMeasurer GetMeasurerC()
{
FieldInfo lengthField = typeof(Widget).GetField(nameof(Widget.Length));
var emitter = Emit<WidgetMeasurer>.NewDynamicMethod()
.LoadArgument(0)
.LoadFieldAddress(lengthField)
.Return();
return emitter.CreateDelegate();
}
This fails at NewDynamicMethod, throwing 'The return Type contains some invalid type (i.e. null, ByRef)'. Which makes sense, since I understand that under the hood WidgetMeasurer returns an Int32&.
The question is, is there some first- or third-party technique I can employ to emit code mimicking the first two examples (which I empirically know work correctly)? If not, is this restriction a logical one?
EDIT: I've tried the equivalent System.Reflection.Emit code and got the same exception (as expected):
WidgetMeasurer GetMeasurerD()
{
FieldInfo lengthField = typeof(Widget).GetField(nameof(Widget.Length));
Type returnType = typeof(int).MakeByRefType();
Type[] paramTypes = { typeof(Widget) };
DynamicMethod method = new DynamicMethod("", returnType, paramTypes);
ILGenerator il = method.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, lengthField);
il.Emit(OpCodes.Ret);
return (WidgetMeasurer)method.CreateDelegate(typeof(WidgetMeasurer));
}
I don't know why this limitation exists for DynamicMethod, but the following worked for me. One difference is that we are defining our own dynamic assembly by hand. Another difference is that since this is separate assembly, Widget needs to be public (or if you name the dynamic assembly appropriately you could use InternalsVisibleTo on the parent assembly).
static void Main(string[] args)
{
var widget = new Widget();
GetLengthMeasurer()(widget) = 7;
Console.WriteLine(widget.Length);
}
private static WidgetMeasurer GetLengthMeasurer()
{
var fieldInfo = typeof(Widget).GetField("Length");
var asmName = new AssemblyName("WidgetDynamicAssembly." + Guid.NewGuid().ToString());
var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndCollect);
var moduleBuilder = asmBuilder.DefineDynamicModule("<Module>");
var typeBuilder = moduleBuilder.DefineType("WidgetHelper");
var methodBuilder = typeBuilder.DefineMethod("GetLength", MethodAttributes.Static | MethodAttributes.Public, typeof(int).MakeByRefType(), new[] { typeof(Widget) });
var ilGen = methodBuilder.GetILGenerator();
ilGen.Emit(OpCodes.Ldarg_0);
ilGen.Emit(OpCodes.Ldflda, fieldInfo);
ilGen.Emit(OpCodes.Ret);
var type = typeBuilder.CreateType();
var mi = type.GetMethod(methodBuilder.Name);
var del = (WidgetMeasurer)mi.CreateDelegate(typeof(WidgetMeasurer));
return del;
}
Output:
7

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);

Generate DynamicMethod from MethodInfo

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!

Reflection.Emit: How to convert MethodBuilder to RuntimeMethodInfo reliably?

After generating a type dynamically and calling TypeBuilder.CreateType, I want to create a delegate that points to a method in the new type. But if I use code like
loadedType = typeBuilder.CreateType();
myDelegate = (MyDelegate)Delegate.CreateDelegate(
typeof(MyDelegate), methodBuilder);
Reusing the methodBuilder as a methodInfo, I get the exception "MethodInfo must be a RuntimeMethodInfo". Now normally I can re-acquire the MethodInfo with
MethodInfo mi = loadedType.GetMethod(methodBuilder.Name);
myDelegate = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate), mi);
But my class may contain several overloaded methods with the same name. How do I make sure I get the right one? Do methods have some persistent identifier I could look up in loadedType?
Update: okay, here's what I'm using to re-acquire the MethodInfo. I just wish I could be sure it works in all cases.
private static MethodInfo ReacquireMethod(Type type, MethodInfo method)
{
BindingFlags flags = BindingFlags.DeclaredOnly;
flags |= (method.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic);
flags |= (method.IsStatic ? BindingFlags.Static : BindingFlags.Instance);
MethodInfo m = type.GetMethod(method.Name, flags, null,
ParameterTypes(method), null);
Debug.Assert(m != null);
return m;
}
As far as I'm aware there's no persistent shared identifier.
Overloads of a method are distinguished by their parameter lists, so my guess is that you'll need to call GetParameters on methodBuilder and then translate the returned ParameterInfo[] array into a Type[] array to pass to the the appropriate GetMethod overload:
MethodInfo mi = loadedType.GetMethod(
methodBuilder.Name,
methodBuilder.GetParameters().Select(p => p.ParameterType).ToArray());
You need to use the GetMethod overload that takes an array of types. Method overloads are selected for binding by the parameters passed to them. Since you are not actually calling a method when getting their metadata via reflection, you have to provide an ordered array of Type objects to get the right MethodInfo object:
Type.GetMethod Method (String, Type[])
Used like:
MethodInfo mi = loadedType.GetMethod(
methodBuilder.Name,
new[]
{
typeof(string),
typeof(int)
}
);
Assiming methodBuilder.Name is "MyMethod", that would bind the following:
public <returnType> MyMethod(string param1, int param2);
Remember that the return type is not a part of a method signature, only the method name and its parameter types are.

Categories

Resources