Learn Roslyn Now: Part 16 The Emit API

Up until now, we’ve mostly looked at how we can use Roslyn to analyze and manipulate source code. Now we’ll take a look at finishing the compilation process by emitting it disk or to memory. To start, we’ll just try emitting a simple compilation to disk and checking whether or not it succeeded.

After running this code we can see that our executable and .pdb have been emitted to Debug/bin/. We can double click output.exe and see that our program runs as expected. Keep in mind that the .pdb file is optional. I’ve only chosen to emit it here to show off the API. Writing the .pdb file to disk can take a fairly long time and it often pays to omit this argument unless you really need it.

Sometimes we might not want to emit to disk. We might just want to compile the code, emit it to memory and then execute it from memory. Keep in mind that for most cases where we’d want to do this, the scripting API probably makes more sense to use. Still, it pays to know our options.

Finally, what if we want to influence  how our code is compiled? We might want to allow unsafe code, mark warnings as errors or delay sign the assembly. All of these options can be customized by passing a CSharpCompilationOptions object to CSharpCompilation.Create(). We’ll take a look at how we can interact with a few of these properties below.

In total there are about twenty-five different options available for customization. Basically any option you have within the Visual Studio’s project property page should be available here.

Advanced options

There are a few optional parameters available in Compilation.Emit() that are worth discussing. Some of them I’m familiar with, but others I’ve never used.

  • xmlDocPath – Auto generates XML documentation based on the documentation comments present on your classes, methods, properties etc.
  • manifestResources – Allows you to manually embed resources such as strings and images within the emitted assembly. Batteries are not included with this API and it requires some heavy lifting if you want to embed .resx resources within your assembly. We’ll explore this overload in a future blog post.
  • win32ResourcesPath – Path of the file from which the compilation’s Win32 resources will be read (in RES format). Unfortunately I haven’t used this API yet and I’m not at all familiar with Win32 Resources.
  • There is also the option to EmitDifference between two compilations. I’m not familiar with this API, and I’m not familiar with how you can apply these deltas to existing assemblies on disk or in memory. I hope to learn more about this API in the coming months.

That just about wraps up the Emit API. If you have any questions, feel free to ask them in the comments below.

Advertisements
This entry was posted in Uncategorized. Bookmark the permalink.

10 Responses to Learn Roslyn Now: Part 16 The Emit API

  1. Dudi Keleti says:

    Nice post as always.
    The EmitDifference is how Edit And Continue works. In general, you need to create a baseline compilation and then you can get the deltas between the baesline and the current state.

  2. Doug says:

    Great articles! I was curious if there was a way to Emit to memory streams like:
    using( var dllStream = new System.IO.MemoryStream() )
    using( var pdbStream = new System.IO.MemoryStream() )
    {
    var result = compilation.Emit( dllStream, pdbStream );

    and then load the new assembly and pdb:

    var assembly = System.Reflection.Assembly.Load( dllStream.ToArray(), pdbStream.ToArray() );

    When I do this the assembly loads, but Visual Studio’s output logs:
    Loaded ‘Test.dll’. Cannot find or open the PDB file.

    Is there something I’m doing wrong, or is it just not possible to do this?

    • joshvarty says:

      It should be possible. The compilation is succeeding in your example? (No compilation errors or anything?)

      • Doug says:

        Oddly it is still logging the same error, but it seems to be working and I’m able to set breakpoints in the test file. I was passing in the wrong Text.Encoding to ParseText() at first (I was passing in UTF8 instead of ASCII) and that was causing the debugger to think the file had changed. So it seems to be working fine now except for the VS log that claims it cannot find or open the PDB file.

      • Doug says:

        One last question. Do you know if there is a way to enable Edit & Continue when loading using Assembly.Load?

      • joshvarty says:

        Sorry I just noticed your last comment today. EnC as I understand requires two processes. One (the debugger process) must pause the other’s CLR so code stops being executed and instead tell the CLR to load new code before telling it to continue. Is this how you’re trying to do things with Assembly.Load?

        I’m not aware of any restrictions on assemblies loaded with Assembly.Load. In fact, that’s how I’m using EnC. Are you seeing errors?

  3. Doug says:

    I’m doing a CSharpCompilation.Emit() into a memory stream and then a Assembly.Load() on that. The debugger will hit breakpoints in the file loaded by the assembly load, but EnC does not occur if I make a change and then step. The (older) docs seem to mention it not working when using ‘Attach To’ (vs. starting the application in VS), so I’m guessing it’s something along those lines. I’ll have to try EnC on an assembly built normally, but loaded with Assembly.Load.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s