通过在 Roslyn c# 中添加属性和默认值来修改函数声明参数



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

基于:https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis 我已经在这个问题中创建了一些基础:查找所有未使用 Roslyn 继承 C# 类并更改为从基本对象继承(类似 java)

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

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);

是我实现创建等于节点的失败尝试。

据我了解,这部分:

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中给我新的参数节点,所以我需要添加默认值设置。如果我对此属性有误,请纠正我,我想知道如何正确构建这个等于表达式节点。

你有两个错误:

  • System.Runtime.CompilerServices.CallerMemberName限定名称,其中包含System.Runtime.CompilerServices作为限定名称CallerMemberName作为标识符名System.Runtime.CompilerServices包含System.Runtime作为限定名称CompilerServices作为标识符名。最后System.Runtime包含两个标识符名称

    因此,您需要修复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(""))));
    

顺便说一下,您可以使用一些有用的 Nodes 方法,如示例ParameterSyntax.WithDefault,当您想要对现有节点进行小更改然后重新调整速度时,可以使用 Node 的副本(SyntaxTree 在 Roslyn 中是不可变的)。

如果您查看以下方法的 Roslyn 报价器,则可以获取生成所需代码所需的代码:

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("")
)
)
);

最新更新