2013-11-22 216 views
3

获取迭代次数与微软罗斯林我有这样的代码来解析:从循环条件

int[] tab1 = { 0, 1, 2, 3, 4 }; 
for (var i = 0; i < tab1.Length - 1; i++) { }; 

我怎样才能tab1.Length的精确值 - 1(4本示例)使用Microsoft罗斯林?

我能找到表达tab1.Length - 1与此代码:

var collector = new ForCollector(); 
foreach (var statement in collector.ForStatements) 
{ 
    Console.WriteLine(statement.Condition.ChildNodes().ElementAt(1)); 
} 

凡ForCollector是一个类继承SyntaxWalker与重载函数VisitForStatement但我不知道如何让tab1.Length的价值。我想我必须为此使用SemanticModel。

罗斯林的版本 - 2012年9月

+0

我不明白。你不需要在你的循环中写'i'吗? –

+1

当tab1是一个方法的参数时它应该返回什么?或者,如果它取决于用户输入?或者,如果它的长度是用“随机”计算的? – svick

+0

什么版本的Roslyn? – kakridge

回答

1

该解决方案走的语法树找到你要找的内容。备注:

  1. 它走过整棵树。如果你放更多的类或方法,它只会找到第一个。您可以修改代码以查找尽可能多的for循环,然后检查每个循环。
  2. 我已经在方法中包装了代码片段,以便于解析。
  3. 我已经打破了每一步的可读性,您可以折叠它们。

以下是源代码,您可以将其转储到控制台应用程序中进行运行。

using System.Linq; 
using Roslyn.Compilers.CSharp; 

// Snip some console app wrapping 

var code = @" 
    public void FindI() 
    { 
     int[] tab1 = { 0, 1, 2, 3, 4 }; 
     for (var i = 0; i < tab1.Length - 1; i++) { }; 
    }"; 

     var syntaxTree = SyntaxTree.ParseText(code); 

     var forStatement = syntaxTree 
      .GetRoot() 
      .DescendantNodes() 
      .OfType<ForStatementSyntax>() 
      .First(); 

     // Gets the name 'tab1' from the for statement condition 
     var conditionMemberName = forStatement 
      .DescendantNodes() 
      .OfType<MemberAccessExpressionSyntax>() 
      .First() 
      .GetFirstToken() 
      .Value; 

     // Finds the first variable: int[] tab1 = { 0, 1, 2, 3, 4 }; 
     var member = syntaxTree 
      .GetRoot() 
      .DescendantNodes() 
      .OfType<VariableDeclarationSyntax>() 
      .First() 

     // Finds the variable with the correct name 'tab1' 
     var variable = member.Variables.Where(x => x.Identifier.Value == conditionMemberName).Single(); 

     // Find the initializer: { 0, 1, 2, 3, 4 }; 
     var initializer = variable.Initializer.Value as InitializerExpressionSyntax; 

     // Counds the number of items in the initializer 
     var lengthOfInitializers = initializer.Expressions.Count; 
+0

为什么不用'Cast()'作为for语句和变量声明?它会让你的代码更短,更干。 – svick

+0

我不明白如何使用Cast()来写入所有内容(WET)。它只会在每个解析结束时删除“as”语句。至于缩短代码,我在文章的第(3)部分提到,我把东西放在很长的格式中,以便更容易理解。 –

+1

你必须先指定你想'SyntaxKind.ForStatement',然后它是'ForStatementSyntax'。我认为这是值得避免的重复。我也不认为用这种方式编写它会使它更容易理解。 – svick