Using C# 6 features with CodeDomProvider (Roslyn)

Update: March 2018

Word of caution, NuGet version 1.0.6 … 1.0.8 will
not copy the /roslyn folder to the build output directory on non-web
projects. Best stick with 1.0.5
https://github.com/aspnet/RoslynCodeDomProvider/issues/38

Run-time compilation using C#6 features requires a new compiler, as @thomas-levesque mentioned. This compiler can be installed by using the nuget package Microsoft.CodeDom.Providers.DotNetCompilerPlatform.

For desktop applications, there’s a problem. The ASP.NET team, in their infinite wisdom have hard-coded the path to the compiler as <runtime-directory>\bin\roslyn\csc.exe See discussion at https://github.com/dotnet/roslyn/issues/9483

If your desktop application is compiled to \myapp\app.exe, the roslyn compiler will be located at \myapp\roslyn\csc.exe, BUT THE CSharpCodeProvider WILL RESOLVE csc.exe as \myapp\bin\roslyn\csc.exe

As far as I can tell, you have two options

  1. Create a post-build and/or installation routine that will move the \roslyn subdirectory to \bin\roslyn.
  2. Fix the runtime code through reflection black magic.

Here is #2, by exposing the CSharpCodeProvider as a property in a utility class.

using System.Reflection;
using Microsoft.CodeDom.Providers.DotNetCompilerPlatform;

static Lazy<CSharpCodeProvider> CodeProvider { get; } = new Lazy<CSharpCodeProvider>(() => {
    var csc = new CSharpCodeProvider();
    var settings = csc
        .GetType()
        .GetField("_compilerSettings", BindingFlags.Instance | BindingFlags.NonPublic)
        .GetValue(csc);

    var path = settings
        .GetType()
        .GetField("_compilerFullPath", BindingFlags.Instance | BindingFlags.NonPublic);

    path.SetValue(settings, ((string)path.GetValue(settings)).Replace(@"bin\roslyn\", @"roslyn\"));

    return csc;
});

Leave a Comment