Comment compiler une solution C# avec Roslyn?
j'ai un logiciel qui génère du code pour un projet C# basé sur les actions des utilisateurs. J'aimerais créer une interface graphique pour compiler automatiquement la solution afin de ne pas avoir à charger Visual Studio juste pour déclencher une recompilation.
je cherchais une chance de jouer un peu avec Roslyn et j'ai décidé d'essayer D'utiliser Roslyn au lieu de msbuild pour faire ça. Malheureusement, je ne trouve pas de bonnes ressources pour utiliser Roslyn de cette façon.
quelqu'un Peut-il point moi dans la bonne direction?
2 réponses
vous pouvez charger la solution en utilisant Roslyn.Services.Workspace.LoadSolution
. Une fois que vous avez fait cela, vous devez passer en revue chacun des projets dans l'ordre de la dépendance, obtenir le Compilation
pour le projet et l'appel Emit
.
Vous pouvez obtenir les compilations dans l'ordre des dépendances avec le code comme ci-dessous. (Oui, je sais que ça craint D'avoir à faire un casting à IHaveWorkspaceServices. Ce sera mieux dans la prochaine version publique, je le promets).
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);
}
}
}
}
1: LoadSolution
utilise toujours msbuild sous les couvertures pour analyser les .csproj fichiers et déterminer les fichiers / références / options du compilateur.
Note2: comme Roslyn n'est pas encore langue complète, il y aura probablement des projets qui ne compilent pas avec succès lorsque vous tenterez cela.
Logiciel Utilisé
Visual Studio Community 2015 Update 1
Microsoft.CodeAnalysis v1.1.0.0 (installé en utilisant la Console du Gestionnaire de paquets avec la commande 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;
}
}
}