如何以编程方式使用 Roslyn 编译 C# 文件?

How to compile a C# file with Roslyn programmatically?

我了解到您无法使用 CSharpCodeProvider 编译 C# 6.0,因此尝试使用 Roslyn。但是我找不到如何加载文件然后将其编译为 dll 的好示例。

我应该如何使用 Roslyn 编写类似于此代码的内容?或者还有其他方法吗?现在,当我尝试使用 C# 6.0 代码编译包含对项目的引用的文件时,它只会说 "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 ""; 
    }

总之我想:

您必须使用 NuGet 包 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
    }
}

我已经创建了一个示例供您使用。您需要调整它以使用 .Net 4.6 的 运行 时间,以便您可以使用 CSharp6 版本。我添加了一些细节,以便您可以选择编译选项。

需要更改 - 将 运行time 的路径更改为目标 .Net 4.6 在下面的示例中将 LanguageVersion.Csharp5 更改为 LanguageVersion.Csharp6

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

这需要一些小的调整,但它应该会给你想要的结果。随意更改。