向 var 类型的变量添加新项 - 在一个变量中具有构造函数和方法声明
Adding new items to a variable of type var - Having Constructor and Method declarations in one variable
我有以下代码:
var allclasses = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach (var memcls in allclasses)
{
if (memcls != null)
{
var methodDeclarations = memcls.DescendantNodes().OfType<MethodDeclarationSyntax>();
foreach (var memmeth in methodDeclarations)
{
var paramDeclaratons = memmeth.ParameterList.Parameters;
在定义 methodDeclarations 的行之后,我还想添加一行,如下面的伪代码:
methodDeclarations.AddRange(
memcls.DescendantNodes().OfType<ConstructorDeclarationSyntax>())
为了将返回的 ConstructorDeclarationSyntax 项也添加到同一 methodDeclarations 变量;即,在同一个变量中同时包含 ConstructorDeclarationSyntax 和 MethodDeclarationSyntax 项。我怎样才能做到这一点?
我尝试了一些类型转换并使用 List 而不是 var 作为 methodDeclarations 变量,但它在我想访问 ParameterList、Identifier 和 memmeth 上的其他属性的下一行中给出了错误。
作为另一个技巧,我尝试使用以下代码
var methodDeclarations = tree.GetRoot().DescendantNodes()
.Where(c => c is MethodDeclarationSyntax || c is ConstructorDeclarationSyntax);
但随后在代码后面访问 ParameterList 和 Identifier 属性时再次出现错误。
如@Chris 所述,如果共享基础 class 没有您想要的适当属性,您可能应该使用两个单独的列表。
但是,如果您确实想要使用单个列表,则以下方法可行:
var methodDeclarations =
tree.GetRoot()
.DescendantNodes()
.Where(c => c is MethodDeclarationSyntax || c is ConstructorDeclarationSyntax)
.Cast<dynamic>();
foreach (var memmeth in methodDeclarations)
{
// Run-time checking so no syntax error
Console.WriteLine(memmeth.Identifier);
}
但是请注意,这会降低性能,因为需要反射,并且您还会失去编译器通常会提供的所有良好的静态语法检查。
您可以按如下方式使用 List<BaseMethodDeclarationSyntax>
:
var methods = new List<BaseMethodDeclarationSyntax>();
methods.AddRange(memcls.DescendantNodes().OfType<MethodDeclarationSyntax>());
methods.AddRange(memcls.DescendantNodes().OfType<ConstructorDeclarationSyntax>());
在该列表中的方法上,您可以使用在 BaseMethodDeclarationSyntax
上声明的所有属性,包括
- 正文
- 表达式主体
- 参数列表
- ...
但你是对的,那里没有标识符 属性,原因很简单:并非每个 BaseMethodDeclarationSyntax 都有一个。具有标识符 属性 的是 MethodDeclarationSyntax、ConstructorDeclarationSyntax 和 DestructorDeclarationSyntax。没有的是 OperatorDeclarationSyntax 和 ConversionOperatorDeclarationSyntax。
但是,您可以轻松地从那些具有标识符的类型中获取标识符。最有效的方法可能是使用访问者:
internal sealed class IdentifierVisitor : CSharpSyntaxVisitor<SyntaxToken>
{
public static IdentifierVisitor Instance { get; } = new IdentifierVisitor();
public override SyntaxToken VisitMethodDeclaration(MethodDeclarationSyntax node)
=> node.Identifier;
public override SyntaxToken VisitConstructorDeclaration(ConstructorDeclarationSyntax node)
=> node.Identifier;
public override SyntaxToken VisitDestructorDeclaration(DestructorDeclarationSyntax node)
=> node.Identifier;
}
一旦你有了那个class,你就可以得到标识符如下:
foreach (var method in methods)
{
var identifier = IdentifierVisitor.Instance.Visit(method);
// for example:
Console.WriteLine(identifier.Text);
}
这适用于常规方法、构造函数和析构函数。
在某种程度上,它也适用于运算符和转换运算符,除了那些 return 默认标记。所以你可以这样做:
var methods = memcls
.DescendantNodes()
.OfType<BaseMethodDeclarationSyntax>()
.ToList();
foreach (var method in methods)
{
var identifier = IdentifierVisitor.Instance.Visit(method);
if (!identifier.IsKind(SyntaxKind.None))
{
Console.WriteLine(identifier.Text);
}
}
最后一件事:调用 .DescendentNodes() 将为您提供整个 ClassDeclarationSyntax 树中的每个节点。您可能应该改用 .Members 。这不会为您提供嵌套 classes 中的方法(尽管如果您需要它们,您可以轻松地递归地获得这些方法),但它会更有效率。
我有以下代码:
var allclasses = tree.GetRoot().DescendantNodes().OfType<ClassDeclarationSyntax>();
foreach (var memcls in allclasses)
{
if (memcls != null)
{
var methodDeclarations = memcls.DescendantNodes().OfType<MethodDeclarationSyntax>();
foreach (var memmeth in methodDeclarations)
{
var paramDeclaratons = memmeth.ParameterList.Parameters;
在定义 methodDeclarations 的行之后,我还想添加一行,如下面的伪代码:
methodDeclarations.AddRange(
memcls.DescendantNodes().OfType<ConstructorDeclarationSyntax>())
为了将返回的 ConstructorDeclarationSyntax 项也添加到同一 methodDeclarations 变量;即,在同一个变量中同时包含 ConstructorDeclarationSyntax 和 MethodDeclarationSyntax 项。我怎样才能做到这一点?
我尝试了一些类型转换并使用 List 而不是 var 作为 methodDeclarations 变量,但它在我想访问 ParameterList、Identifier 和 memmeth 上的其他属性的下一行中给出了错误。
作为另一个技巧,我尝试使用以下代码
var methodDeclarations = tree.GetRoot().DescendantNodes()
.Where(c => c is MethodDeclarationSyntax || c is ConstructorDeclarationSyntax);
但随后在代码后面访问 ParameterList 和 Identifier 属性时再次出现错误。
如@Chris 所述,如果共享基础 class 没有您想要的适当属性,您可能应该使用两个单独的列表。
但是,如果您确实想要使用单个列表,则以下方法可行:
var methodDeclarations =
tree.GetRoot()
.DescendantNodes()
.Where(c => c is MethodDeclarationSyntax || c is ConstructorDeclarationSyntax)
.Cast<dynamic>();
foreach (var memmeth in methodDeclarations)
{
// Run-time checking so no syntax error
Console.WriteLine(memmeth.Identifier);
}
但是请注意,这会降低性能,因为需要反射,并且您还会失去编译器通常会提供的所有良好的静态语法检查。
您可以按如下方式使用 List<BaseMethodDeclarationSyntax>
:
var methods = new List<BaseMethodDeclarationSyntax>();
methods.AddRange(memcls.DescendantNodes().OfType<MethodDeclarationSyntax>());
methods.AddRange(memcls.DescendantNodes().OfType<ConstructorDeclarationSyntax>());
在该列表中的方法上,您可以使用在 BaseMethodDeclarationSyntax
上声明的所有属性,包括
- 正文
- 表达式主体
- 参数列表
- ...
但你是对的,那里没有标识符 属性,原因很简单:并非每个 BaseMethodDeclarationSyntax 都有一个。具有标识符 属性 的是 MethodDeclarationSyntax、ConstructorDeclarationSyntax 和 DestructorDeclarationSyntax。没有的是 OperatorDeclarationSyntax 和 ConversionOperatorDeclarationSyntax。
但是,您可以轻松地从那些具有标识符的类型中获取标识符。最有效的方法可能是使用访问者:
internal sealed class IdentifierVisitor : CSharpSyntaxVisitor<SyntaxToken>
{
public static IdentifierVisitor Instance { get; } = new IdentifierVisitor();
public override SyntaxToken VisitMethodDeclaration(MethodDeclarationSyntax node)
=> node.Identifier;
public override SyntaxToken VisitConstructorDeclaration(ConstructorDeclarationSyntax node)
=> node.Identifier;
public override SyntaxToken VisitDestructorDeclaration(DestructorDeclarationSyntax node)
=> node.Identifier;
}
一旦你有了那个class,你就可以得到标识符如下:
foreach (var method in methods)
{
var identifier = IdentifierVisitor.Instance.Visit(method);
// for example:
Console.WriteLine(identifier.Text);
}
这适用于常规方法、构造函数和析构函数。 在某种程度上,它也适用于运算符和转换运算符,除了那些 return 默认标记。所以你可以这样做:
var methods = memcls
.DescendantNodes()
.OfType<BaseMethodDeclarationSyntax>()
.ToList();
foreach (var method in methods)
{
var identifier = IdentifierVisitor.Instance.Visit(method);
if (!identifier.IsKind(SyntaxKind.None))
{
Console.WriteLine(identifier.Text);
}
}
最后一件事:调用 .DescendentNodes() 将为您提供整个 ClassDeclarationSyntax 树中的每个节点。您可能应该改用 .Members 。这不会为您提供嵌套 classes 中的方法(尽管如果您需要它们,您可以轻松地递归地获得这些方法),但它会更有效率。