2015-09-24 67 views
19

我讀過你不能用CSharpCodeProvider編譯C#6.0,因此試圖用Roslyn來完成。但我找不到一個很好的例子,如何加載一個文件,然後將其編譯爲一個dll。如何以編程方式使用Roslyn編譯C#文件?

我應該如何寫一些類似於Roslyn的代碼?或者還有其他方法可以做到嗎?現在,當我嘗試編譯包含對C#6.0代碼項目引用的文件時,它只是說「類型或名稱空間名稱'x'不存在於命名空間'y'中(您是否缺少程序集引用?」)

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 ""; 
    } 

總之我想:

  • 加載一個C#文件
  • 把它編譯成一個dll,所以我可以在以後加載它。
+0

關於類似主題的另一篇文章:[嘗試以編程方式編譯和執行C#代碼](https://stackoverflow.com/q/10314815/4975230) – jrh

回答

21

我已經創建了一個示例供您使用。您需要調整它以使用.Net 4.6的運行時間,以便您可以使用CSharp6版本。我添加了一些細節,以便您可以選擇編輯選項。

需要更改 - 更改運行時的路徑LanguageVersion.Csharp5LanguageVersion.Csharp6面向.NET 4.6 變化低於樣本。

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

這將需要很小的調整,但它應該給你想要的結果。如你所願改變它。

+0

這工作完美,謝謝! – user1776562

+0

可以讓我知道我需要什麼參考/包來使這個工作?謝謝。 –

+1

Microsoft.CodeAnalysis.CSharp該軟件包也將安裝其他依賴項。 – vendettamit

8

你必須使用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 
    } 
}