Search code examples
c#dllwin-universal-approslyncodedom

Roslyn - CodeDom: HowTo dynamically compile Code to Universal-Windows-Library


I am generating a .NET Dll dynamically containing wrapper classes for a WPF Project. I am doing it with the System.CodeDom.Compiler.CodeDomProvider class.

Now I have to create a wrapper class for a Universal-Windows-Dll. Since the System.CodeDom.Compiler.CodeDomProvider class still uses the old .NET Compiler I had to Switch to the new Roslyn Compiler (by adding the Nuget Package Microsoft.CodeDom.Providers.DotNetCompilerPlatform). Then I replaced the instantiation of the code-dom-Provider with the new CSharpCodeProvider.

new Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider();

The Code compiles fine but I found no way to set the TargetFramework / CompilerVersion. The old CodeDomProvider had the CompilerOptions where I was able to specify the CompilerVersion ect. But the new Roslyn does not have this Option (or I was to stupid to find it).

The result is that it compiles the DLL as a normal .NET 4.x Dll. But I Need a Universal-Windows Dll since it is used in a Universal-Project.

Browsing the Internet I found many different ways to use the Roslyn Compiler. Most of them seem to be from old Beta-Versions of the Compiler, therefore none of them works. The Roslyn.Compilers Namespace (which was used in most examples) seems to be the Namespace from the betas.

Does someone know how to use the roslyn Compiler properly? I don't want to modify the Compiler. I simply want to generate a DLL dynamically by compiling it from SourceCode, but I have to specify the Platform Target.


Solution

  • There's an option to reference the compiler and runtime version. The latest release of Roslyn have this new feature that you can specify which target framework you want to use and which version of compiler you want to use.

    I was also looking around to explore latest Roslyn library to compile a CSharp6 version program to compile against 4.6 framework. Below is my working sample.

    Note, runtimepath variable which is pointing to .Net framework libraries and CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6) option in Parser.

     public class Program
        {
            private static readonly IEnumerable<string> DefaultNamespaces =
                new[]
                {
                    "System", 
                    "System.IO", 
                    "System.Net", 
                    "System.Linq", 
                    "System.Text", 
                    "System.Text.RegularExpressions", 
                    "System.Collections.Generic"
                };
    
            private static string runtimePath = @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6\{0}.dll";
    
            private static readonly IEnumerable<MetadataReference> DefaultReferences =
                new[]
                {
                    MetadataReference.CreateFromFile(string.Format(runtimePath, "mscorlib")),
                    MetadataReference.CreateFromFile(string.Format(runtimePath, "System")),
                    MetadataReference.CreateFromFile(string.Format(runtimePath, "System.Core"))
                };
    
            private static readonly CSharpCompilationOptions DefaultCompilationOptions =
                new CSharpCompilationOptions(OutputKind.WindowsRuntimeApplication)
                        .WithOverflowChecks(true)
                        .WithOptimizationLevel(OptimizationLevel.Release)
                        .WithUsings(DefaultNamespaces);
    
            public static SyntaxTree Parse(string text, string filename = "", CSharpParseOptions options = null)
            {
                var stringText = SourceText.From(text, Encoding.UTF8);
                return SyntaxFactory.ParseSyntaxTree(stringText, options, filename);
            }
    
            public static void Main(string[] args)
            {
                //ReferenceFinder finder = new ReferenceFinder();
                //finder.Find("Read");
    
                var fileToCompile = @"C:\Users\..\Documents\Visual Studio 2013\Projects\SignalR_Everything\Program.cs";
                var source = File.ReadAllText(fileToCompile);
                var parsedSyntaxTree = Parse(source, "", CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp6));
    
                var compilation
                    = CSharpCompilation.Create("Test.dll", new SyntaxTree[] { parsedSyntaxTree }, DefaultReferences, DefaultCompilationOptions);
                try
                {
                    var result = compilation.Emit(@"c:\temp\Test.dll");
    
                    Console.WriteLine(result.Success ? "Sucess!!" : "Failed");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex);
                }
                Console.Read();
            }
        }