我正在使用MSBuildWorkspace,需要分析C#解决方案中的错误。我不需要实际的编译结果(文件),而只是错误。
使用MSBuildWorkspace从解决方案中获取错误列表的最快方法是什么?
答案 0 :(得分:2)
您需要加载解决方案,然后遍历项目并查找所有错误。这不会创建任何文件(即,不会发出IL),但确实需要其余大部分编译器管道(词法分析,解析,绑定等)。
//Replace with the correct filepath
var filePath = @"SomeSolution.sln";
var msbws = MSBuildWorkspace.Create();
var soln = await msbws.OpenSolutionAsync(filePath);
foreach(var proj in soln.Projects)
{
var name = proj.Name;
var compilation = await proj.GetCompilationAsync();
var errors = compilation.GetDiagnostics().Where(n => n.Severity == DiagnosticSeverity.Error).ToList();
// TODO: Do something with the errors
}
如果您知道要打开哪个项目(可以忽略其他项目),则也可以使用OpenProjectAsync
。
答案 1 :(得分:1)
JoshVarty's Answer可以使用,但是可能无法正确定位MSBuild版本以便运行分析。这是针对最新的roslyn api(版本2.9)的完整示例:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Build.Locator;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.MSBuild;
using Microsoft.CodeAnalysis.Text;
class Program
{
static async Task Main(string[] args) {
// Attempt to set the version of MSBuild.
var visualStudioInstances = MSBuildLocator.QueryVisualStudioInstances().ToArray();
var instance = visualStudioInstances.Length == 1
// If there is only one instance of MSBuild on this machine, set that as the one to use.
? visualStudioInstances[0]
// Handle selecting the version of MSBuild you want to use.
: SelectVisualStudioInstance(visualStudioInstances);
Console.WriteLine($"Using MSBuild at '{instance.MSBuildPath}' to load projects.");
// NOTE: Be sure to register an instance with the MSBuildLocator
// before calling MSBuildWorkspace.Create()
// otherwise, MSBuildWorkspace won't MEF compose.
MSBuildLocator.RegisterInstance(instance);
using (var workspace = MSBuildWorkspace.Create()) {
// Print message for WorkspaceFailed event to help diagnosing project load failures.
workspace.WorkspaceFailed += (o, e) => Console.WriteLine(e.Diagnostic.Message);
var solutionPath = args[0];
Console.WriteLine($"Loading solution '{solutionPath}'");
// Attach progress reporter so we print projects as they are loaded.
var solution = await workspace.OpenSolutionAsync(solutionPath, new ConsoleProgressReporter());
Console.WriteLine($"Finished loading solution '{solutionPath}'");
// Print the number of errors found for each project
foreach(var project in solution.Projects) {
var name = project.Name;
var compilation = await project.GetCompilationAsync();
var errors = compilation.GetDiagnostics().Where(n => n.Severity == DiagnosticSeverity.Error);
Console.WriteLine($"project '{name}' contained '{errors.Count()}');
}
}
}
private static VisualStudioInstance SelectVisualStudioInstance(VisualStudioInstance[] visualStudioInstances) {
Console.WriteLine("Multiple installs of MSBuild detected please select one:");
for (int i = 0; i < visualStudioInstances.Length; i++) {
Console.WriteLine($"Instance {i + 1}");
Console.WriteLine($" Name: {visualStudioInstances[i].Name}");
Console.WriteLine($" Version: {visualStudioInstances[i].Version}");
Console.WriteLine($" MSBuild Path: {visualStudioInstances[i].MSBuildPath}");
}
while (true) {
var userResponse = Console.ReadLine();
if (int.TryParse(userResponse, out int instanceNumber) &&
instanceNumber > 0 &&
instanceNumber <= visualStudioInstances.Length) {
return visualStudioInstances[instanceNumber - 1];
}
Console.WriteLine("Input not accepted, try again.");
}
}
private class ConsoleProgressReporter : IProgress<ProjectLoadProgress> {
public void Report(ProjectLoadProgress loadProgress) {
var projectDisplay = Path.GetFileName(loadProgress.FilePath);
if (loadProgress.TargetFramework != null) {
projectDisplay += $" ({loadProgress.TargetFramework})";
}
Console.WriteLine($"{loadProgress.Operation,-15} {loadProgress.ElapsedTime,-15:m\\:ss\\.fffffff} {projectDisplay}");
}
}
}