2012-11-07 20 views
19

Tôi có một phần mềm tạo mã cho dự án C# dựa trên hành động của người dùng. Tôi muốn tạo một GUI để tự động biên dịch các giải pháp vì vậy tôi không phải tải lên Visual Studio chỉ để kích hoạt một biên dịch lại.Làm cách nào để biên dịch một giải pháp C# với Roslyn?

Tôi đã tìm kiếm một cơ hội để chơi với Roslyn một chút và quyết định thử và sử dụng Roslyn thay vì msbuild để thực hiện việc này. Thật không may, tôi dường như không thể tìm thấy bất kỳ tài nguyên tốt nào khi sử dụng Roslyn theo cách này.

Có ai có thể chỉ cho tôi đúng hướng không?

Trả lời

22

Bạn có thể tải giải pháp bằng cách sử dụng Roslyn.Services.Workspace.LoadSolution. Một khi bạn đã làm như vậy, bạn cần phải đi qua từng dự án theo thứ tự phụ thuộc, nhận được Compilation cho dự án và gọi Emit trên đó.

Bạn có thể nhận được bộ sưu tập theo thứ tự phụ thuộc với mã như dưới đây. (Vâng, tôi biết rằng phải bỏ qua IHaveWorkspaceServices. Nó sẽ tốt hơn trong bản phát hành công khai tiếp theo, tôi hứa).

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

Lưu ý1: LoadSolution vẫn sử dụng msbuild dưới bìa để phân tích cú pháp tệp .csproj và xác định tùy chọn tệp/tham chiếu/trình biên dịch.

Lưu ý2: Vì Roslyn chưa hoàn thành ngôn ngữ, có thể sẽ có các dự án không biên dịch thành công khi bạn thử.

+0

Có một cách thuận tiện để xác định thứ tự phụ thuộc (như 'sln.ProjectsInDependencyOrder') hoặc là một cái gì đó này, tôi sẽ phải thực hiện trên của riêng tôi? (ví dụ: Đi qua tham chiếu dự án và xây dựng cây phụ thuộc) – NobodysNightmare

+1

Có một IProjectDependencyService có GetTopologicallySortedProjects(). Tôi không có máy tính tiện dụng để kiểm tra chính xác cách nhận, nhưng sẽ cập nhật sau. –

+0

Đã chỉnh sửa câu trả lời để thêm một số mã. –

8

Tôi cũng muốn biên dịch một giải pháp đầy đủ khi đang di chuyển. Xây dựng từ Kevin Pilch-Bisson's answerJosh E's comment, tôi đã viết mã để biên dịch chính nó và ghi nó vào tệp.

Phần mềm sử dụng

Visual Studio 2015 Cộng đồng Cập nhật 1

Microsoft.CodeAnalysis v1.1.0.0 (cài đặt sử dụng Package Manager Console bằng lệnh Install-Package Microsoft.CodeAnalysis).

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

Không tìm thấy giá trị nào cho RuntimeMetadataVersion. Không có assembly nào chứa System.Object được tìm thấy cũng không phải là giá trị cho RuntimeMetadataVersion được chỉ định thông qua các tùy chọn. – Aflred

+0

FYI để sử dụng ví dụ này, bạn cũng sẽ cần phải cài đặt Microsoft.Build.Tasks.Core và Microsoft.Build gói –

+0

Điều này dường như là một câu trả lời tốt hơn nhiều vì không gian tên roslyn.services đã lỗi thời. –

Các vấn đề liên quan