通过在 Roslyn c# 中添加属性和默认值来修改函数声明参数
Modifying function declaration parameter by adding attribute and default value in Roslyn c#
我正在使用 Roslyn 在 C# 中修改我早期的代码分析器,但我再次遇到一些我不知道如何应用的更改。
基于:https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis I've created some base to work with in this question:
我分析并遍历了树以查找所有方法声明及其参数。基于 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
中给我新的参数节点,该节点已经包含属性,因此我需要添加默认值设置。如果我对此属性有误,请纠正我,我想知道如何正确构建这个 equals 表达式节点。
如果您查看以下方法的 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("")
)
)
);
你有两个错误:
System.Runtime.CompilerServices.CallerMemberName
是包含 System.Runtime.CompilerServices
[ 的 QualifiedName =51=] 作为 QualifiedName 和 CallerMemberName
作为 IdentifierName。 System.Runtime.CompilerServices
包含 System.Runtime
作为 QualifiedName 和 CompilerServices
作为 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 中是不可变的)节点然后替换它。
我正在使用 Roslyn 在 C# 中修改我早期的代码分析器,但我再次遇到一些我不知道如何应用的更改。
基于:https://github.com/dotnet/roslyn/wiki/Getting-Started-C%23-Syntax-Analysis I've created some base to work with in this question:
我分析并遍历了树以查找所有方法声明及其参数。基于 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
中给我新的参数节点,该节点已经包含属性,因此我需要添加默认值设置。如果我对此属性有误,请纠正我,我想知道如何正确构建这个 equals 表达式节点。
如果您查看以下方法的 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("")
)
)
);
你有两个错误:
System.Runtime.CompilerServices.CallerMemberName
是包含System.Runtime.CompilerServices
[ 的 QualifiedName =51=] 作为 QualifiedName 和CallerMemberName
作为 IdentifierName。System.Runtime.CompilerServices
包含System.Runtime
作为 QualifiedName 和CompilerServices
作为 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 中是不可变的)节点然后替换它。