我有以下代码:
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 for methodDeclarations变量,但是它在下一行中给出错误,我想在memmeth上访问ParameterList,Identifier和其他属性。
另一个技巧是,我尝试使用以下代码
var methodDeclarations = tree.GetRoot().DescendantNodes()
.Where(c => c is MethodDeclarationSyntax || c is ConstructorDeclarationSyntax);
但是后来它再次在代码中访问ParameterList和Identifier属性时出错。
答案 0 :(得分:1)
正如@Chris所提到的,如果共享基类没有你想要的适当属性,你应该使用两个单独的列表。
但是,如果确实想要使用单个列表,则以下内容将起作用:
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);
}
但请注意,由于需要进行反射,因此性能较差,并且您还会丢失通常由编译器提供的所有良好的静态语法检查。
答案 1 :(得分:1)
您可以按如下方式使用List<BaseMethodDeclarationSyntax>
:
var methods = new List<BaseMethodDeclarationSyntax>();
methods.AddRange(memcls.DescendantNodes().OfType<MethodDeclarationSyntax>());
methods.AddRange(memcls.DescendantNodes().OfType<ConstructorDeclarationSyntax>());
在该列表中的方法中,您可以使用BaseMethodDeclarationSyntax
上声明的所有属性,包括
但你是对的,那里没有Identifier属性,原因很简单:并非每个BaseMethodDeclarationSyntax都有一个。具有Identifier属性的是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;
}
获得该课程后,您可以获得如下标识符:
foreach (var method in methods)
{
var identifier = IdentifierVisitor.Instance.Visit(method);
// for example:
Console.WriteLine(identifier.Text);
}
这适用于常规方法,构造函数和析构函数。 在某种程度上,它也适用于运算符和转换运算符,除了那些将返回默认令牌。所以你可以这样做:
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代替。这不会给你嵌套类中的方法(尽管如果你需要它们可以很容易地递归那些),但它会更有效率。