【问题标题】:Modifying function declaration parameter by adding attribute and default value in Roslyn c#通过在Roslyn c#中添加属性和默认值来修改函数声明参数
【发布时间】:2017-09-20 19:00:04
【问题描述】:

我正在使用 Roslyn 在 C# 中修改我早期的代码分析器,但我再次遇到了一些我不知道如何应用的更改。

基于:https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis我已经创建了一些基础来解决这个问题:Finding all not inheriting C# classes with Roslyn and changing to inheriting from base object (java-like)

我已解析并遍历树以查找所有方法声明及其参数。基于 VS Syntax Visualiser,我构建了这个:

foreach (var c in root1.DescendantNodesAndSelf())
{
    var methodDeclaration = c as MethodDeclarationSyntax;

    if (methodDeclaration == null)
        continue;

    if (methodDeclaration.ParameterList != null) //Have parameters
    {
        foreach (var p in methodDeclaration.ParameterList.Parameters)
        {
            var parameter = p as ParameterSyntax;
            String name, type;
            name = parameter.GetLastToken().Value.ToString();
            type = parameter.GetFirstToken().Value.ToString();

            if (parameter == null)
                continue;

            if (name == "caller" && type == "string")
            {
                AttributeSyntax ats = SyntaxFactory.Attribute(SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System.Runtime.CompilerServices"),SyntaxFactory.IdentifierName("CallerMemberName")));
                SeparatedSyntaxList<AttributeSyntax> ssl = new SeparatedSyntaxList<AttributeSyntax>();
                ssl = ssl.Add(ats);
                AttributeListSyntax als = SyntaxFactory.AttributeList(ssl);
                var par1 = parameter.AddAttributeLists(als);
                //ExpressionSyntax es = SyntaxFactory.AssignmentExpression(SyntaxKind.EqualsValueClause,null,SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression))
                //SyntaxFactory.EqualsValueClause(es);
                par1 = par1.AddModifiers();
                root2 = root2.ReplaceNode(parameter, par1);
            }
        }
    }
    else //Don't have parameters
        continue;

}

我正在尝试转换这样声明的方法:

private void testM3(string caller)

进入

private void testM3([System.Runtime.CompilerServices.CallerMemberName] string caller = "")

这部分:

//ExpressionSyntax es = SyntaxFactory.AssignmentExpression(SyntaxKind.EqualsValueClause,null,SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression))
//SyntaxFactory.EqualsValueClause(es);

是我创建equals节点的失败尝试。

据我了解,这部分:

AttributeSyntax ats = SyntaxFactory.Attribute(SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System.Runtime.CompilerServices"),SyntaxFactory.IdentifierName("CallerMemberName")));
SeparatedSyntaxList<AttributeSyntax> ssl = new SeparatedSyntaxList<AttributeSyntax>();
ssl = ssl.Add(ats);
AttributeListSyntax als = SyntaxFactory.AttributeList(ssl);
var par1 = parameter.AddAttributeLists(als);

会在var par1 中给我新的参数节点,它已经包含属性,所以我需要添加默认值设置。如果我对这个属性有错误,请纠正我,我想知道如何正确构建这个等于表达式节点。

【问题讨论】:

    标签: c# roslyn parse-tree


    【解决方案1】:

    你有两个错误:

    • System.Runtime.CompilerServices.CallerMemberNameQualifiedName,其中包含 System.Runtime.CompilerServices 作为 QualifiedNameCallerMemberName 作为标识符名称System.Runtime.CompilerServices 包含 System.Runtime 作为 QualifiedNameCompilerServices 作为 IdentifierName .最后 System.Runtime 包含两个 IdentifierName

      因此您需要修复AttributeSyntax 的创建,如下面的代码所示:

          AttributeSyntax ats = SyntaxFactory.Attribute(
                              SyntaxFactory.QualifiedName(
                                  SyntaxFactory.QualifiedName(
                                      SyntaxFactory.QualifiedName(SyntaxFactory.IdentifierName("System"), SyntaxFactory.IdentifierName("Runtime")), 
                                      SyntaxFactory.IdentifierName("CompilerServices")),
                              SyntaxFactory.IdentifierName("CallerMemberName")));
      
    • EqualsValueClause 不应包含AssignmentExpression,而应直接包含某种LiteralExpression。你的情况是StringLiteralExpression:

      var par1 = parameter
                          .AddAttributeLists(als)
                          .WithDefault(SyntaxFactory.EqualsValueClause(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal(""))));
      

    顺便说一句,当您想对现有节点进行小更改然后替换时,您可以使用一些有用的节点方法,例如ParameterSyntax.WithDefault,来创建节点的副本(SyntaxTree 在 Roslyn 中是不可变的)它。

    【讨论】:

      【解决方案2】:

      如果您查看Roslyn Quoter 的以下方法,您可以获得生成所需代码所需的代码:

      public void GetSomething([CallerMemberName] string test=""){
      
      }
      

      您会注意到参数中的默认值是使用以下方法构造的(roslyn 引用器通常省略 SyntaxFactory):

      .WithDefault(SyntaxFactory.EqualsValueClause(
                          SyntaxFactory.LiteralExpression(
                                 SyntaxKind.StringLiteralExpression,
                                 SyntaxFactory.Literal("")
                                 )
                          )
                   );
      

      因此,为了将您的 EqualsValueClause 添加为默认值,您只需通过在参数上调用上述代码(而不是未注释的代码)来替换现有的默认值:

       par1 = par1.WithDefault(SyntaxFactory.EqualsValueClause(
                          SyntaxFactory.LiteralExpression(
                                 SyntaxKind.StringLiteralExpression,
                                 SyntaxFactory.Literal("")
                                 )
                          )
                   );
      

      【讨论】:

        猜你喜欢
        • 2021-07-04
        • 2012-08-11
        • 2016-07-03
        • 1970-01-01
        • 2020-09-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多