I recently bought Ayende's book Building DSLs in Boo (buy it, read it, it's awesome) but I'm coming up against an implementation problem and I want to see what the generated code looks like. I would normally use reflector to look at the code but in this case the assemblies are dynamic and only in memory. Is there a way to save dynamic assemblies to disk so that I can reflect them?
EDIT / My Answer:
Wow, it took awhile to come back to this one. Unfortunately I left an important bit out from the original question.
Important Bit: I'm using Ayende's RhinoDSL library as he recommends in the book. I have access to the boo compiler in my subclass of DslEngine which looks like this:
public class JobEngine : DslEngine
{
protected override void CustomizeCompiler(Boo.Lang.Compiler.BooCompiler compiler, Boo.Lang.Compiler.CompilerPipeline pipeline, string[] urls)
{
pipeline.Insert(1, new ImplicitBaseClassCompilerStep(typeof (JobBase), "Prepare", "JobLanguage", "log4net", "Quartz"));
}
}
To change the least and get what I wanted I needed to add one line...
public class JobEngine : DslEngine
{
protected override void CustomizeCompiler(Boo.Lang.Compiler.BooCompiler compiler, Boo.Lang.Compiler.CompilerPipeline pipeline, string[] urls)
{
compiler.Parameters.GenerateInMemory = false; // <--- This one.
pipeline.Insert(1, new ImplicitBaseClassCompilerStep(typeof (JobBase), "Prepare", "JobLanguage", "log4net", "Quartz"));
}
}
This caused the compiler to output the assembly to my ~\LocalSettings\Temp directory and then I could then reflect it. It's important to note that making that change caused the rest of the program to break (RhinoDSL could no longer find the assemblies in memory because I output them to disk), so this is only useful as a debugging tool.
There may be an easier way to do it, but if you don't mind using WinDbg you can save any loaded managed assembly from memory (WinDbg uses the term module, but it works for managed assemblies as well).
Use the
!savemodule
command with the address of the assembly. If you don't have the address use thelm vm
command with the module name. Following that you get a regular DLL assembly, that you can inspect in Reflector.Of course you may also just look at the IL code in memory.
If you can get the Assembly at runtime.
i.e.
You can then cast this assembly into AssemblyBuilder and call the Save method.
Yes, the
AssemblyBuilder
class has aSave
method for this purpose. You need to use the appropriate mode for this, which is most likelyRunAndSave
:Look up where BooCompiler is instantiated, change the pipeline from CompileToMemory to CompileToFile