Не удается получить SyntaxTree из объекта компиляции - PullRequest
0 голосов
/ 06 марта 2019

Я новичок в roslyn, поэтому я попытался начать его изучение с создания очень простого консольного приложения, которое представлено на известном учебном сайте.(https://riptutorial.com/roslyn/example/16545/introspective-analysis-of-an-analyzer-in-csharp), и он не работал должным образом.

Созданное мною приложение Cosole предназначено для .NET Framework (целевая версия 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();
        }
    }
}

Моя проблема заключается в том, что свойство SyntaxTrees объекта Compilation возвращаетNULL в значке [** 2]. Естественно, следующий метод FirstOrDefault возвращает значение NULL.

Я пробовал несколько других кодов. Я обнаружил, что могу получить SyntaxTree из текста кода CSharp, используя метод CSharpSyntaxTree.ParseText. НоЯ не смог получить ничего из исходного кода, по последовательности

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

Что я хотел бы знать, так это то, что я что-то упускаю, чтобы получить информацию о синтаксисе из исходного кода, используя описанный выше процесс.

Я буду признателен, если кто-нибудь даст мне хороший совет.

Ответы [ 2 ]

0 голосов
/ 18 марта 2019

Я искал различные примеры программ в сети и нашел самый надежный и самый безопасный метод. Решение состоит в том, чтобы создать статический метод, который возвращает 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());
    }
}

Конечно, для практического использования требуется много улучшений.

0 голосов
/ 08 марта 2019

MsBuildWorkspace не будет работать правильно, если у вас нет тех же перенаправлений в файле app.config вашего приложения, что и в msbuild.exe.config. Без перенаправлений, вероятно, не удается загрузить библиотеки msbuild. Вам нужно найти файл msbuild.exe.config, который находится в вашей системе, и скопировать элементы <assemblyBinding>, относящиеся к сборкам Microsoft.Build, в ваш файл app.config. Убедитесь, что вы поместили их в правильную конфигурацию элементов / время выполнения.

...