2013-11-22 2 views
3

У меня есть этот код для синтаксического анализа:Получение числа итераций с Microsoft Рослин из условия цикла

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

+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