2017-08-03 43 views
3

我有以下代码:添加新项目类型VAR的变量 - 在具有构造函数和方法声明一个变量

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

为了具有被返回加入到相同methodDeclarations变量以及所述ConstructorDeclarationSyntax物品;即,具有同一变量中的ConstructorDeclarationSyntax和MethodDeclarationSyntax项目。我怎样才能做到这一点?

我尝试了一些类型强制转换,并使用List代替var for methodDeclarations变量,但随后出现错误,我想在memmeth上访问ParameterList,Identifier和其他属性。

至于另一个伎俩,我尝试使用下面的代码

var methodDeclarations = tree.GetRoot().DescendantNodes() 
    .Where(c => c is MethodDeclarationSyntax || c is ConstructorDeclarationSyntax); 

但随后又给出了稍后在代码中访问参数列表和标识性的错误。

+2

你需要告诉我们更多关于有问题的类。例如,如果您将methodDeclarations设置为该类型的列表,那么“MethodDeclarationSyntax”和“ConstructorDeclarationSyntax”的常见基类型是什么,那么您应该可以将它们添加到同一个列表中。当然,如果该基类没有“ParameterList”属性,那么你尝试访问它就会失败。你会在这种情况下发生什么? – Chris

+1

这些是Microsoft.CodeAnalysis.CSharp.Syntax名称空间中的Roslyn类型,如下所述:http://www.coderesx.com/roslyn/html/9139EA6B.htm MethodDeclarationSyntax和ConstructorDeclarationSyntax都具有ParameterList和Identifier属性,但它们的基类BaseMethodDeclarationSyntax ,例如没有标识符属性 – Supernova

+0

您是否尝试过'List methodDeclarations = ...',因为这看起来是基本类型? – Equalsk

回答

1

可以使用List<BaseMethodDeclarationSyntax>如下:

var methods = new List<BaseMethodDeclarationSyntax>(); 
methods.AddRange(memcls.DescendantNodes().OfType<MethodDeclarationSyntax>()); 
methods.AddRange(memcls.DescendantNodes().OfType<ConstructorDeclarationSyntax>()); 

在该列表中的方法,您可以使用BaseMethodDeclarationSyntax声明的所有特性,包括

  • 身体
  • ExpressionBody
  • ParameterList
  • ...

但是你说得对,那里没有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。这不会给你嵌套类中的方法(尽管如果你需要它们,你可以很容易地递归),但它会更加高效。

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

但是请注意,这是需要思考这将是少高性能和你也失去了所有的很好的静态语法检查,通常由编译器提供。

相关问题