2012-11-07 16 views
19

Ich habe eine Software, die basierend auf Benutzeraktionen Code für ein C# -Projekt generiert. Ich würde gerne eine GUI erstellen, um die Lösung automatisch zu kompilieren, so dass ich Visual Studio nicht laden muss, nur um eine Neukompilierung auszulösen.Wie kompiliere ich eine C# -Lösung mit Roslyn?

Ich war auf der Suche nach einer Chance, mit Roslyn ein bisschen zu spielen und entschied mich, Roslyn anstelle von Msbuild zu verwenden, um dies zu tun. Leider kann ich keine guten Quellen finden, Roslyn auf diese Weise zu benutzen.

Kann mir jemand in die richtige Richtung zeigen?

Antwort

22

Sie können die Lösung laden, indem Sie Roslyn.Services.Workspace.LoadSolution verwenden. Sobald Sie dies getan haben, müssen Sie jedes der Projekte in Abhängigkeitsreihenfolge durchlaufen, erhalten Sie die Compilation für das Projekt und rufen Sie Emit darauf.

Sie können die Compilations in Abhängigkeitsreihenfolge mit Code wie unten erhalten. (Ja, ich weiß, dass das Ignorieren von IHaveWorkspaceServices zum Scheitern verurteilt ist. Es wird besser in der nächsten öffentlichen Version sein, das verspreche ich).

using Roslyn.Services; 
using Roslyn.Services.Host; 
using System; 
using System.Collections.Generic; 
using System.IO; 

class Program 
{ 
    static void Main(string[] args) 
    { 
     var solution = Solution.Create(SolutionId.CreateNewId()).AddCSharpProject("Foo", "Foo").Solution; 
     var workspaceServices = (IHaveWorkspaceServices)solution; 
     var projectDependencyService = workspaceServices.WorkspaceServices.GetService<IProjectDependencyService>(); 
     var assemblies = new List<Stream>(); 
     foreach (var projectId in projectDependencyService.GetDependencyGraph(solution).GetTopologicallySortedProjects()) 
     { 
      using (var stream = new MemoryStream()) 
      { 
       solution.GetProject(projectId).GetCompilation().Emit(stream); 
       assemblies.Add(stream); 
      } 
     } 
    } 
} 

Hinweis 1: LoadSolution tut immer noch Verwendung msbuild unter der Decke der CSPROJ Dateien zu analysieren und die Dateien/references/Compiler-Optionen zu bestimmen.

Hinweis2: Da Roslyn noch nicht vollständig ist, gibt es wahrscheinlich Projekte, die nicht erfolgreich kompiliert werden, wenn Sie dies versuchen.

+0

Gibt es eine bequeme Möglichkeit, die Abhängigkeit der Reihenfolge der Bestimmung (wie 'sln.ProjectsInDependencyOrder') oder ist dies etwas, was ich würde in meinem eigenen implementieren? (z. B. Durchlaufen von Projektreferenzen und Erstellen einer Abhängigkeitsstruktur) – NobodysNightmare

+1

Es gibt einen IProjectDependencyService mit GetTopologicSortedProjects(). Ich habe keinen Computer zur Hand, um genau zu prüfen, wie ich ihn bekomme, aber ich werde ihn später aktualisieren. –

+0

Bearbeitete die Antwort, um etwas Code hinzuzufügen. –

8

Ich wollte auch eine vollständige Lösung im laufenden Betrieb kompilieren. Gebaut von Kevin Pilch-Bisson's answer und Josh E's comment, schrieb ich Code, um selbst zu kompilieren und in Dateien zu schreiben.

Software Gebraucht

Visual Studio Community-2015-Update 1

Microsoft.CodeAnalysis v1.1.0.0 (installiert mit Package Manager-Konsole mit dem Befehl Install-Package Microsoft.CodeAnalysis).

-Code

using System; 
using System.Collections.Generic; 
using System.IO; 
using Microsoft.CodeAnalysis; 
using Microsoft.CodeAnalysis.Emit; 
using Microsoft.CodeAnalysis.MSBuild; 

namespace Roslyn.TryItOut 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      string solutionUrl = "C:\\Dev\\Roslyn.TryItOut\\Roslyn.TryItOut.sln"; 
      string outputDir = "C:\\Dev\\Roslyn.TryItOut\\output"; 

      if (!Directory.Exists(outputDir)) 
      { 
       Directory.CreateDirectory(outputDir); 
      } 

      bool success = CompileSolution(solutionUrl, outputDir); 

      if (success) 
      { 
       Console.WriteLine("Compilation completed successfully."); 
       Console.WriteLine("Output directory:"); 
       Console.WriteLine(outputDir); 
      } 
      else 
      { 
       Console.WriteLine("Compilation failed."); 
      } 

      Console.WriteLine("Press the any key to exit."); 
      Console.ReadKey(); 
     } 

     private static bool CompileSolution(string solutionUrl, string outputDir) 
     { 
      bool success = true; 

      MSBuildWorkspace workspace = MSBuildWorkspace.Create(); 
      Solution solution = workspace.OpenSolutionAsync(solutionUrl).Result; 
      ProjectDependencyGraph projectGraph = solution.GetProjectDependencyGraph(); 
      Dictionary<string, Stream> assemblies = new Dictionary<string, Stream>(); 

      foreach (ProjectId projectId in projectGraph.GetTopologicallySortedProjects()) 
      { 
       Compilation projectCompilation = solution.GetProject(projectId).GetCompilationAsync().Result; 
       if (null != projectCompilation && !string.IsNullOrEmpty(projectCompilation.AssemblyName)) 
       { 
        using (var stream = new MemoryStream()) 
        { 
         EmitResult result = projectCompilation.Emit(stream); 
         if (result.Success) 
         { 
          string fileName = string.Format("{0}.dll", projectCompilation.AssemblyName); 

          using (FileStream file = File.Create(outputDir + '\\' + fileName)) 
          { 
           stream.Seek(0, SeekOrigin.Begin); 
           stream.CopyTo(file); 
          } 
         } 
         else 
         { 
          success = false; 
         } 
        } 
       } 
       else 
       { 
        success = false; 
       } 
      } 

      return success; 
     } 
    } 
} 
+0

Kein Wert für RuntimeMetadataVersion gefunden. Es wurde keine Assembly gefunden, die System.Object enthält, und für RuntimeMetadataVersion wurde kein Wert über Optionen angegeben. – Aflred

+0

Um dieses Beispiel zu verwenden, müssen Sie auch Microsoft.Build.Tasks.Core und Microsoft.Build Packages installieren –

+0

Dies scheint eine viel bessere Antwort zu sein, da der Namespace roslyn.services veraltet ist. –

Verwandte Themen