2013-11-22 215 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