4

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?

riQQ
  • 9,878
  • 7
  • 49
  • 66
Robert J.
  • 645
  • 5
  • 13
  • How do you generate IL with CodeDom without building an assembly? – Simon Mourier Apr 24 '13 at 12:54
  • Well i just realized that it will create a temporary file behind the scenes anyway even if you set CompilerParameters.GenerateInMemory to true. However, of course i am *building* the assembly, my question was about working with the results in memory. – Robert J. Apr 24 '13 at 13:17
  • Cecil relies on it's own assembly loader, so it can't use the CompilerResults.CompiledAssembly property, but that should not be a problem since, as you found out, CodeDom always build a real file behind the scene event with GenerateInMemory=true (that's because CSC always works out-of-process, unlike something like Roslyn http://stackoverflow.com/questions/7852926/microsoft-roslyn-vs-codedom). So, I believe you can just point Cecil to load the assembly from CompilerResults.PathToAssembly – Simon Mourier Apr 24 '13 at 15:18
  • Obviously i can't use CompilerResults.CompiledAssembly, but the *bytecode* that i have should be understandable to Cecil. But yes, im working with Temporary files now, and it works, it's just not as elegant as doing it all in memory would've been. However, since that is not possible at all with CodeDom, i think its fine. Thanks for your comments! – Robert J. Apr 24 '13 at 15:24

1 Answers1

0

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);
riQQ
  • 9,878
  • 7
  • 49
  • 66