43

I read that you can't compile C# 6.0 with CSharpCodeProvider and therefor trying to do with with Roslyn. But I can't find a good example how to load a file and then compile it to a dll.

How should I write something similar to this code with Roslyn? Or is there some other way to do it? Now when I try to compile files that contain reference to projects with C# 6.0 code it just say "The type or namespace name 'x' does not exist in the namespace 'y' (are you missing an assembly reference?)"

    public string CompileCode()
    {
        var provider = new CSharpCodeProvider();
        var outputPath = Path.Combine(Path.GetDirectoryName(_path), $"Code.dll");
        var compilerparams = new CompilerParameters(_referencedAssemblies, outputPath);
        CompilerResults results = provider.CompileAssemblyFromFile(compilerparams, _path);
        var dllPath = results.PathToAssembly;
        if (!results.Errors.HasErrors)
            return dllPath;
        PrintError(results.Errors);
        return ""; 
    }

In summary I want to:

  • Load a C# file
  • Compile it to a dll so I can load it later.
MilleB
  • 1,470
  • 2
  • 19
  • 32
  • Another post on a similar topic: [trying to compile and execute C# code programmatically](https://stackoverflow.com/q/10314815/4975230) – jrh Jan 30 '18 at 17:40

2 Answers2

40

I have created a sample for you to work with. You need to tweak it to use the run time for .Net 4.6 so that CSharp6 version is availble to you. I have added little details so that you can choose the options of compilations.

Changes required - Change the path of runtime to target .Net 4.6 Change the LanguageVersion.Csharp5 to LanguageVersion.Csharp6 in below sample.

 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.5.1\{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.DynamicallyLinkedLibrary)
                    .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);
        }

        static void Main(string[] args)
        {
            var fileToCompile = @"C:\Users\DesktopHome\Documents\Visual Studio 2013\Projects\ConsoleForEverything\SignalR_Everything\Program.cs";
            var source = File.ReadAllText(fileToCompile);
            var parsedSyntaxTree = Parse(source, "", CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp5));

            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();
        }

This would need little tweaks but it should give you desired results. Change it as you may wish.

vendettamit
  • 14,315
  • 2
  • 32
  • 54
  • Can yo utell me what references/packages I need to get this to work? Thanks. – Binary Worrier Apr 03 '17 at 11:33
  • 1
    Microsoft.CodeAnalysis.CSharp this package will install other dependencies as well. – vendettamit Apr 03 '17 at 13:34
  • Do not put `.dll` on the [CSharpCompilation.Create](https://learn.microsoft.com/en-us/dotnet/api/microsoft.codeanalysis.csharp.csharpcompilation.create?view=roslyn-dotnet#Microsoft_CodeAnalysis_CSharp_CSharpCompilation_Create_System_String_System_Collections_Generic_IEnumerable_Microsoft_CodeAnalysis_SyntaxTree__System_Collections_Generic_IEnumerable_Microsoft_CodeAnalysis_MetadataReference__Microsoft_CodeAnalysis_CSharp_CSharpCompilationOptions), had a lot of work today to figure out this, thanks for the answer. –  Oct 11 '19 at 00:49
  • What about compiling multiple cs files to one dll? – Jamaxack Feb 27 '20 at 07:52
24

You have to use the NuGet package Microsoft.CodeAnalysis.CSharp.

var syntaxTree = CSharpSyntaxTree.ParseText(source);

CSharpCompilation compilation = CSharpCompilation.Create(
    "assemblyName",
    new[] { syntaxTree },
    new[] { MetadataReference.CreateFromFile(typeof(object).Assembly.Location) },
    new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

using (var dllStream = new MemoryStream())
using (var pdbStream = new MemoryStream())
{
    var emitResult = compilation.Emit(dllStream, pdbStream);
    if (!emitResult.Success)
    {
        // emitResult.Diagnostics
    }
}
meziantou
  • 20,589
  • 7
  • 64
  • 83
  • Why do we have to get an external NuGet package for this? Is Roslyn not part of the .NET framework? – user3700562 May 30 '19 at 10:56
  • 3
    Roslyn in not part of the .NET Framework, so you have to get it with a NuGet package. CodeDom is part of the .NET Framework, but I think it supports only c# 5. – meziantou May 30 '19 at 13:48
  • @meziantou how to support some default libraries with this code? I have tried to do `using System.Linq;` and got compilation error `The type or namespace name 'Linq' does not exist in the namespace 'System' (are you missing an assembly reference?)` – Andrew_STOP_RU_WAR_IN_UA Sep 19 '21 at 21:43
  • You can download the package `Microsoft.NETCore.App.Ref` or `Microsoft.NETFramework.ReferenceAssemblies.net48` and reference the dll from the lib folder. You can find useful packages here https://github.com/meziantou/Meziantou.Analyzer/blob/7a9367bbeb89970802615a69ab67779e37043a82/tests/Meziantou.Analyzer.Test/Helpers/ProjectBuilder.Validation.cs#L162 – meziantou Sep 19 '21 at 22:47