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);
Related
I want to IL generate a dynamic method
delegate ArraySegment<byte> X(MyClass mc);
that calls a method of the signature on mc and returns its out parameter.
MethodInfo methInf = aClass.GetMethod("Y",
BindingFlags.Public | BindingFlags.Instance,
null, new[] { typeof(ArraySegment<byte>).MakeByRefType() }, null);
but I don't know how to handle the out parameter. Here's the code I have so far.
DynamicMethod dm = new DynamicMethod("X", typeof(ArraySegment<byte>),
new[] { typeof(MyClass) });
ILGenerator il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.EmitCall(OpCodes.Callvirt, methInf, null);
What's needed to make the out param work?
Thanks #MarcGravell (also for your deleted answer, which was of great help, as it spells out what you hint at in your comment to my question) and ILSpy, which helped me by compiling c# code to CIL, so I could just peek at that.
So here's the final, working code:
LocalBuilder local = il.DeclareLocal(typeof(ArraySegment<byte>));
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldloca, local);
il.EmitCall(OpCodes.Callvirt, methInf, null);
il.Emit(OpCodes.Pop);
il.Emit(OpCodes.Ldloc, local.LocalIndex);
il.Emit(OpCodes.Ret);
Invoking this is 10 times faster than doing methodInfo.Invoke(...) (on a methodInfo object that was created only once, of course).
I want this test to pass:
[Test]
public void LambdaTest()
{
var m = Expression.Lambda(typeof(Func<int>), Expression.Constant(0)).Compile();
Assert.That(m.Method.DeclaringType, Is.Not.Null);
}
This is necessary to make stack-walking lagacy code to work correctly. What's the simpliest way to do it?
I would prefer the most portable way.
You can build a new type at runtime and then compile the expression into a method of that type.
You need to create a new assembly and a new module at run time. Once you create those, you can use them to create as many types as you like. Here is a code sample to create the assembly and the module:
var assemblyBuilder =
AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName {Name = "MyNewAssembly"},
AssemblyBuilderAccess.Run);
var moduleBuilder = assemblyBuilder.DefineDynamicModule("MyNewModule");
Now, you can use the module builder to define a new type like this:
var typeBuilder = moduleBuilder.DefineType("MyNewType");
And then a new method like this:
var methodBuilder =
typeBuilder.DefineMethod(
"MyNewMethod",
MethodAttributes.Public | MethodAttributes.Static,
typeof(int), //returns an int
new Type[]{}); //takes no parameters
Please note that the method signature should match your expression delegate type.
Next, we compile the expression into the new method using the CompileToMethod method:
var expression = Expression.Lambda(typeof(Func<int>), Expression.Constant(0));
expression.CompileToMethod(methodBuilder);
We generate the actual type from the type builder:
var type = typeBuilder.CreateType();
Then we use the Delegate.CreateDelegate method to create a delegate to the newly created static method like this:
Func<int> func =
(Func<int>)Delegate.CreateDelegate(
typeof(Func<int>),
type.GetMethod("MyNewMethod"));
int value = func(); //Test
Now func.Method.DeclaringType would return our dynamically created type.
You can easily use this code to generate some helper methods to make it easy to use.
Ok, I found it myself but I'm not sure how it will work in .NET Core and which framework may or may not support this. If you have a better (more elegant or portable) solution please feel free to post your answer.
The key is to use CompileToMethod of Lambda expression.
[Test]
public void LambdaTest2()
{
var asm = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName("test"), AssemblyBuilderAccess.Run);
var masm = asm.DefineDynamicModule("main");
var type = masm.DefineType("TestType");
var mb = type.DefineMethod("TestMethod", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[0]);
// your lambda
ConstantExpression expressionTree = Expression.Constant(0);
Expression.Lambda(typeof(Func<int>), expressionTree).CompileToMethod(mb);
var m = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), type.CreateType().GetMethod("TestMethod"));
Assert.That(m.Method.DeclaringType, Is.Not.Null);
// you can create another in the same module but with another type (because type can't be changed)
var type2 = masm.DefineType("TestType2");
var mb2 = type2.DefineMethod("TestMethod2", MethodAttributes.Public | MethodAttributes.Static, typeof(int), new Type[0]);
// your lambda 2
ConstantExpression expresisonTree2 = Expression.Constant(1);
Expression.Lambda(typeof(Func<int>), expresisonTree2).CompileToMethod(mb2);
var m2 = (Func<int>)Delegate.CreateDelegate(typeof(Func<int>), type2.CreateType().GetMethod("TestMethod2"));
Assert.That(m2.Method.DeclaringType, Is.Not.Null);
// check correctness
Assert.That(m(), Is.EqualTo(0));
Assert.That(m2(), Is.EqualTo(1));
}
A lambda expression compiles to a DynamicMethod, which is always null for the DeclaringType property.
See DynamicMethod definition
See this SO answer also
Would make my life easier as well if I could find a way around that.
This sounds like such an obvious thing but I am having a lot of difficulty. Basically, what I'm doing is generating a method using Reflection.Emit and I then want to call it. So far, I have the method building and such, but I can't get a reference to the method after it's built because "The invoked member is not supported before the type is created."
Here is what I basically do:
AssemblyBuilder assembly;
ModuleBuilder module;
TypeBuilder containerTypeBuilder;
Type containerType;
var name = new AssemblyName();
name.Name = "DynamicWrapper";
var domain = Thread.GetDomain();
assembly = domain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
module = assembly.DefineDynamicModule(assembly.GetName().Name, false);
containerTypeBuilder = module.DefineType("__DynamicWrapperType",
TypeAttributes.Public | TypeAttributes.Class |
TypeAttributes.AutoClass |
TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit |
TypeAttributes.AutoLayout, typeof(object));
//build method
var mb = containerTypeBuilder.DefineMethod("generatedmethod" + (unique++),
MethodAttributes.Public | MethodAttributes.Static, typeof (int),
new Type[] {});
//build method body and all that
.....
var type=module.GetType("__DynamicWrapperType");
var info=type.GetMethod(mb.Name, BindingFlags.Static | BindingFlags.Public); //error here
How do I take my freshly built method and load it up so that I can invoke it?
Also, I've tried mb.Invoke, but that yields "The invoked member is not supported in a dynamic module."
If you are creating individual method(s), then DynamicMethod is a much better choice (especially since your method is static) - you just useCreateDelegate (specifying the delegate type), cast to that delegate, and invoke. It is also less overhead, and collectible.
But if you are forced to use MethodBuilder: you must use CreateType on the TypeBuilder, then use reflection on the now real type (returned from CreateType).
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
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!