使用 Roslyn 更改文件

Change files using Roslyn

我正在尝试编写一个命令行工具来使用 Roslyn 修改一些代码。一切似乎都很顺利:打开解决方案,更改解决方案,Workspace.TryApplyChanges 方法 returns 为真。但是,磁盘上没有实际文件发生变化。这是怎么回事?下面是我正在使用的顶级代码。

static void Main(string[] args)
{
    var solutionPath = args[0];
    UpdateAnnotations(solutionPath).Wait();
}

static async Task<bool> UpdateAnnotations(string solutionPath)
{
    using (var workspace = MSBuildWorkspace.Create())
    {
        var solution = await workspace.OpenSolutionAsync(solutionPath);
        var newSolution = await SolutionAttributeUpdater.UpdateAttributes(solution);
        var result = workspace.TryApplyChanges(newSolution);
        Console.WriteLine(result);
        return result;
    }
}

我使用您的代码构建了一个简短的程序并收到了我预期的结果 - 问题似乎出在 SolutionAttributeUpdater.UpdateAttributes 方法中。我使用以下实现和您的基本主要方法和 UpdateAnnotations 方法收到了这些结果:

public class SolutionAttributeUpdater
{
    public static async Task<Solution> UpdateAttributes(Solution solution)
    {
        foreach (var project in solution.Projects)
        {
            foreach (var document in project.Documents)
            {
                var syntaxTree = await document.GetSyntaxTreeAsync();
                var root = syntaxTree.GetRoot();

                var descentants = root.DescendantNodes().Where(curr => curr is AttributeListSyntax).ToList();
                if (descentants.Any())
                {
                    var attributeList = SyntaxFactory.AttributeList(
                        SyntaxFactory.SingletonSeparatedList(
                            SyntaxFactory.Attribute(SyntaxFactory.IdentifierName("Cookies"), SyntaxFactory.AttributeArgumentList(SyntaxFactory.SeparatedList(new[] { SyntaxFactory.AttributeArgument(
                                    SyntaxFactory.LiteralExpression(
                                                                SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(@"Sample"))
                                    )})))));
                    root = root.ReplaceNodes(descentants, (node, n2) => attributeList);
                    solution = solution.WithDocumentSyntaxRoot(document.Id, root);
                }
            }
        }
        return solution;
    }
}

在示例解决方案中使用以下 class 进行了测试:

public class SampleClass<T>
{
    [DataMember("Id")]
    public int Property { get; set; }
    [DataMember("Id")]
    public void DoStuff()
    {
        DoStuff();
    }
}

结果如下:

public class SampleClass<T>
{
[Cookies("Sample")]        public int Property { get; set; }
[Cookies("Sample")]        public void DoStuff()
    {
        DoStuff();
    }
}

如果您看一下 UpdateAttributes 方法,我必须用 ReplaceNodes 替换节点并通过调用 WithDocumentSyntaxRoot 更新解决方案。

我假设这两个调用中的任何一个丢失或者根本没有任何改变 - 如果您调用 workspace.TryApplyChanges(解决方案),您仍然会收到 true 作为输出。

请注意,多次调用 root.ReplaceNode() 而不是 root.ReplaceNodes() 也会导致错误,因为只有第一次更新实际用于修改后的文档 - 这可能会导致你相信什么都没有改变,这取决于实施。