无法从Compilation对象获取SyntaxTree

问题描述 投票:0回答:2

我是roslyn的初学者,所以我尝试通过制作一个非常简单的控制台应用程序来开始学习它,这是在着名的教程网站中引入的。 (https://riptutorial.com/roslyn/example/16545/introspective-analysis-of-an-analyzer-in-csharp),它运作不佳。

我制作的Cosole应用程序是.NET Framework(目标框架版本是4.7.2),而不是.NET Core或.NET标准。我添加了NuGet包Microsoft.CodeAnalysis和Microsoft.CodeAnalysis.Workspaces.MSBuild,然后编写了一个简单的代码,如下所示。

using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.MSBuild;
using System;
using System.Linq;

namespace SimpleRoslynConsole
{
class Program
    {
        static void Main(string[] args)
        {
            // Declaring a variable with the current project file path.
            // *** You have to change this path to fit your development environment.
            const string projectPath =
                @"C:\Users\[MyName]\Source\Repos\RoslynTrialConsole01\RoslynTrialConsole01.csproj";
            var workspace = MSBuildWorkspace.Create();
            var project = workspace.OpenProjectAsync(projectPath).Result;
            // [**1]Getting the compilation.
            var compilation = project.GetCompilationAsync().Result;
            // [**2]As this is a simple single file program, the first syntax tree will be the current file.
            var syntaxTree = compilation.SyntaxTrees.FirstOrDefault();
            if (syntaxTree != null)
            {
                var rootSyntaxNode = syntaxTree.GetRootAsync().Result;
                var firstLocalVariablesDeclaration = rootSyntaxNode.DescendantNodesAndSelf()
                    .OfType<LocalDeclarationStatementSyntax>().First();
                var firstVariable = firstLocalVariablesDeclaration.Declaration.Variables.First();
                var variableInitializer = firstVariable.Initializer.Value.GetFirstToken().ValueText;
                Console.WriteLine(variableInitializer);
            }
            else
            {
                Console.WriteLine("Could not get SyntaxTrees from this projects.");
            }
            Console.WriteLine("Hit any key.");
            Console.ReadKey();
        }
    }
}

我的问题是,Compilation对象的SyntaxTrees属性在[** 2]标记中返回null。当然,在FirstOrDefault方法之后返回null。

我已经尝试了其他几个代码。我发现我可以使用CSharpSyntaxTree.ParseText方法从CSharp代码文本中获取SyntaxTree。但我无法从源代码中获取任何内容

var workspace = MSBuildWorkspace.Create();
var project = workspace.OpenProjectAsync(projectPath).Result;
var compilation = project.GetCompilationAsync().Result;

我想知道的是,如果我错过了一些东西,可以通过上面的过程从源代码中获取语法信息。

我很感激有人给我一个很好的建议。

c# roslyn roslyn-code-analysis
2个回答
0
投票

除非您的应用程序的app.config文件中包含msbuild.exe.config中包含的所有相同重定向,否则MsBuildWorkspace将无法正常工作。没有重定向,它可能无法加载msbuild库。您需要找到系统上的msbuild.exe.config文件,并将与Microsoft.Build程序集相关的<assemblyBinding>元素复制到app.config中。确保将它们放在正确的元素配置/运行时下。


0
投票

我在网上搜索了各种样本程序,找到了最可靠,最安全的方法。解决方案是创建一个静态方法,在指定的File中返回SyntaxTrees,如下所示。

private static Compilation CreateTestCompilation()
{
    var found = false;
    var di = new DirectoryInfo(Environment.CurrentDirectory);
    var fi = di.GetFiles().Where((crt) => { return crt.Name.Equals("program.cs", StringComparison.CurrentCultureIgnoreCase); }).FirstOrDefault();
    while ((fi == null) || (di.Parent == null))
    {
        di = new DirectoryInfo(di.Parent.FullName);
        fi = di.GetFiles().Where((crt) => { return crt.Name.Equals("program.cs", StringComparison.CurrentCultureIgnoreCase); }).FirstOrDefault();
        if (fi != null)
        {
            found = true;
            break;
        }
    }
    if (!found)
    {
        return null;
    }
    var targetPath = di.FullName +  @"\Program.cs";
    var targetText = File.ReadAllText(targetPath);
    var targetTree =
                   CSharpSyntaxTree.ParseText(targetText)
                                   .WithFilePath(targetPath);
    var target2Path = di.FullName + @"\TypeInferenceRewriter.cs";
    var target2Text = File.ReadAllText(target2Path);
    var target2Tree =
                   CSharpSyntaxTree.ParseText(target2Text)
                                   .WithFilePath(target2Path);

    SyntaxTree[] sourceTrees = { programTree, target2Tree };

    MetadataReference mscorlib =
            MetadataReference.CreateFromFile(typeof(object).Assembly.Location);
    MetadataReference codeAnalysis =
            MetadataReference.CreateFromFile(typeof(SyntaxTree).Assembly.Location);
    MetadataReference csharpCodeAnalysis =
            MetadataReference.CreateFromFile(typeof(CSharpSyntaxTree).Assembly.Location);

    MetadataReference[] references = { mscorlib, codeAnalysis, csharpCodeAnalysis };

    return CSharpCompilation.Create("TransformationCS",
                                    sourceTrees,
                                    references,
                                    new CSharpCompilationOptions(
                                            OutputKind.ConsoleApplication));
}

而来电程序将是这样的。

static void Main(string[] args)
{
    var test = CreateTestCompilation();
    if (test == null)
    {
        return;
    }

    foreach (SyntaxTree sourceTree in test.SyntaxTrees)
    {
        Console.WriteLine(souceTree.ToFullString());
    }
}

当然,需要进行许多改进才能将其付诸实践。

© www.soinside.com 2019 - 2024. All rights reserved.