c# - 如何删除所有成员属性但保留空行?

标签 c# roslyn

我写了一个 CSharpSyntaxRewriter,我用它来从方法中删除属性,但是当我从一个方法。

这非常适用于具有多个属性的方法,但不适用于只有一个属性。

这是一个最小的重现:

void Main()
{
    var code = @"namespace P
{
    class Program
    {
        public void NoAttributes() { }
        //???
        [TestCategory(""Atomic"")]
        public void OneAtt1() { }

        [TestCategory(""Atomic"")]
        public void OneAtt2() { }

        [TestMethod, TestCategory(""Atomic"")]
        public void TwoAtts() { }
    }
}";
    var tree = CSharpSyntaxTree.ParseText(code);
    var rewriter = new AttributeRemoverRewriter();

    var rewrittenRoot = rewriter.Visit(tree.GetRoot());

    Console.WriteLine(rewrittenRoot.GetText().ToString());
}

public class AttributeRemoverRewriter : CSharpSyntaxRewriter
{
    public override SyntaxNode VisitAttributeList(AttributeListSyntax attributeList)
    {
        var nodesToRemove =
            attributeList
            .Attributes
            .Where(att => (att.Name as IdentifierNameSyntax).Identifier.Text.StartsWith("TestCategory"))
            .ToArray();

        if (nodesToRemove.Length == attributeList.Attributes.Count)
        {
            //Remove the entire attribute
            return
                attributeList
                .RemoveNode(attributeList, SyntaxRemoveOptions.KeepNoTrivia);
        }
        else
        {
            //Remove just the matching ones recursively
            foreach (var node in nodesToRemove)
                return
                    VisitAttributeList(attributeList.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia));
        }

        return
            base.VisitAttributeList(attributeList);
    }
}

完整版在我的gist 上(在任何人指出任何其他问题之前)。

预期输出是:

namespace P
{
    class Program
    {
        public void NoAttributes() { }
        //???

        public void OneAtt1() { }

        public void OneAtt2() { }

        [TestMethod]
        public void TwoAtts() { }
    }
}

实际输出为:

namespace P
{
  class Program
  {
    public void NoAttributes() { }
    public void OneAtt1() { }
    public void OneAtt2() { }

    [TestMethod]
    public void TwoAtts() { }
  }
}

关于我需要做些什么来保留空白的任何想法(甚至评论!!)?

我把所有我能想到的 Trivia 组合都弄乱了。更改 SyntaxRemoveOptions 会导致 Roslyn 代码库中出现 NullReferenceException,使用 *Trivia 扩展方法会导致属性不再被删除 - 只是空白.

最佳答案

就像我在评论中所说的那样,在我看来它像是 Roslyn 中的一个错误。您可以报告它并根据需要使用以下解决方法。

我只是尝试在方法级别而不是属性级别重写。 (您可以对属性使用类似的方法)

public class AttributeRemoverRewriter : CSharpSyntaxRewriter
{
    public override SyntaxNode VisitMethodDeclaration(MethodDeclarationSyntax node)
    {
        var newAttributes = new SyntaxList<AttributeListSyntax>();

        foreach (var attributeList in node.AttributeLists)
        {
            var nodesToRemove =
            attributeList
           .Attributes
           .Where(att => (att.Name as IdentifierNameSyntax).Identifier.Text.StartsWith("TestCategory"))
           .ToArray();

            if (nodesToRemove.Length == attributeList.Attributes.Count)
            {
                //Do not add the attribute to the list. It's being removed completely.
            }
            else
            {
                //We want to remove only some of the attributes
                var newAttribute = (AttributeListSyntax)VisitAttributeList(attributeList.RemoveNodes(nodesToRemove, SyntaxRemoveOptions.KeepNoTrivia));
                newAttributes = newAttributes.Add(newAttribute);
            }
        }

        //Get the leading trivia (the newlines and comments)
        var leadTriv = node.GetLeadingTrivia();
        node = node.WithAttributeLists(newAttributes);

        //Append the leading trivia to the method
        node = node.WithLeadingTrivia(leadTriv);
        return node;
    }
}

这是我得到的输出。如果您想删除评论,您可以进一步过滤 leadTriv

My output

请注意,这不包括某些...不正常的情况:

[TestCategory(""Atomic"")]
#if Debug
#endif
/*Trivia in unfortunate places*/
[TestCategory("test")]
public void OneAtt2() { }

您将失去属性之间的琐事。琐事是构建重写器时最难做好的事情之一。

关于c# - 如何删除所有成员属性但保留空行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31749997/

相关文章:

c# - 如何删除 StringBuilder 中的 X 和 Y 行?

roslyn - 如何获取由同一类的方法访问的字段和属性?

c# - 我如何通过roslyn找到变量的值

c# - C# 规范 7.16.2.5 中的不一致

c# - 同一列表中的多个泛型类型并调用它们的方法

c# - 为什么我在尝试在 Asp.NetCore 应用程序中包含对 UserServiceBaseLifetime() 的调用时遇到编译器错误?

c# - 处理用户控件 (MVVM) 中的输入手势

c# - GC.KeepAlive 保留上下文

.net - 自编译 Roslyn 构建性能 : Not as fast as originally shipped Roslyn version

c# - Roslyn 分析器代码修复 - 禁用预览选项