2015-01-09 2 views
3

Я работаю над разработкой приложения, которое переписывает код CSharp. Я делаю это с Roslyn. Я столкнулся с проблемой splitting expressions.Разбиение выражений с помощью Roslyn

Sample класс

class Program 
{ 
    static void Main(string[] args) 
    { 
     float floatVariable = 20; 
     Int16 intVariable = 10; 
     string str = "School"; 
     Console.Write(str + floatVariable.ToString() + intVariable.ToString()); // Facing problem with this statement 
    } 
} 

Пример кода Я использую

string code = new StreamReader(classPath).ReadToEnd(); 
var syntaxTree = CSharpSyntaxTree.ParseText(code); 
var syntaxRoot = syntaxTree.GetRoot(); 

//This will get the method and local variables declared inside the method 
var MyMethods = syntaxRoot.DescendantNodes().OfType<MethodDeclarationSyntax>(); 
foreach (MethodDeclarationSyntax mds in MyMethods) 
{ 
    syntaxTree = CSharpSyntaxTree.ParseText(mds.ToFullString()); 
    IEnumerable<SyntaxNode> nodes = syntaxTree.GetRoot().DescendantNodes(); 
    IEnumerable<VariableDeclarationSyntax> variableDeclarations =  nodes.OfType<VariableDeclarationSyntax>(); 
    foreach (VariableDeclarationSyntax variable in variableDeclarations) 
    { 
    // I will collect the variable details like Datatype, variable names and initialized values here 
    } 


    foreach (StatementSyntax statement in mds.Body.Statements) 
    { 
     if (statement.CSharpKind() == SyntaxKind.ExpressionStatement) 
     { 
      //I want to split the expressions "Console.Write(str + floatVariable.ToString() + intVariable.ToString());" as below 

      //1. intVariable.ToString() 
      //2. floatVariable.ToString() 
      //3. str 

      //Then I have to find the whole data type from the resolved result of above 3 => string here    
     } 
    } 
} 

Любая помощь будет оценена.

Edit: У меня возникли проблемы в расщеплении параметризованных инструкций выражения. Я пытаюсь это сделать,

if (statement.CSharpKind() == SyntaxKind.ExpressionStatement) 
{ 
    ExpressionStatementSyntax expression = statement as ExpressionStatementSyntax; 
    var expressions = expression.Expression.DescendantNodes(); 
} 

Но это разделяет каждый токен как отдельный элемент. Я просто хочу, чтобы расколоть Console.Write(str + floatVariable.ToString() + intVariable.ToString()) в,

  1. Console.Write()
  2. ул
  3. intVariable.ToString()
  4. floatVariable.ToString()
+2

код [Рослин Синтаксис дерева Visualiser] (https://visualstudiogallery.msdn.microsoft.com/70e184da-9b3a- 402f-b210-d62a898e2887) может помочь вам здесь. – Rawling

+1

В чем же проблема? Получение выражения параметра из инструкции? Работа с бинарными выражениями для '+'? Что вы пробовали? Как это случилось? – svick

+0

@svick: Я отредактировал вопрос. Пожалуйста, найдите его в блоке ** Изменить **. –

ответ

1

Это трудно чтобы сказать, что именно вы хотите сделать, потому что вы указали, что код должен делать только в одном конкретном случае, а не в общем.

Как я интерпретировать это:

  1. Для выражения вызова, возвращает выражение, которое это время вызывается, а также спуститься в его аргументы, если таковые имеются.
  2. Для двоичных операторов опускайтесь на обоих детей.
  3. Для всех других выражений верните выражение непосредственно.

С помощью этой спецификации и используя CSharpSyntaxVisitor, код может выглядеть следующим образом:

public static IEnumerable<ExpressionSyntax> Split(ExpressionSyntax expression) 
{ 
    return new SplitVisitor().Visit(expression); 
} 

class SplitVisitor : CSharpSyntaxVisitor<IEnumerable<ExpressionSyntax>> 
{ 
    public override IEnumerable<ExpressionSyntax> VisitInvocationExpression(
     InvocationExpressionSyntax node) 
    { 
     yield return node.Expression; 

     var argumentExpressions = node.ArgumentList.Arguments 
      .SelectMany(a => Visit(a.Expression)); 
     foreach (var expression in argumentExpressions) 
      yield return expression; 
    } 

    public override IEnumerable<ExpressionSyntax> VisitBinaryExpression(
     BinaryExpressionSyntax node) 
    { 
     foreach (var expression in Visit(node.Left)) 
      yield return expression; 
     foreach (var expression in Visit(node.Right)) 
      yield return expression; 
    } 

    public override IEnumerable<ExpressionSyntax> DefaultVisit(SyntaxNode node) 
    { 
     var expression = node as ExpressionSyntax; 
     if (expression != null) 
      yield return expression; 
    } 
} 
+0

Вы правильно поняли вопрос, и ваш ответ работал так, как ожидалось. Большое спасибо ... –

+0

Но решение не работает для statment 'Console.Write (str + string.Concat (" str1 "," str2 "))'. Метод ** split ** не управляет вложенными арументами '(" str1 "," str2 ")' in 'string.Concat (" str1 "," str2 "));' [Пожалуйста, найдите изображение для этого здесь ] (http://imgur.com/fW5Hkc1) –

+1

@ MeikandaNayanar.II не понимаю, ваше изображение показывает, что мой разделитель «Split()» разделил вложенную строку.Concat («str1», «str2») в 'string.Concat',' "str1" 'и' "str2" '. Вы говорите, что этого не должно быть? Если это так, то я не понимаю, какие правила вы хотите использовать «Split()». – svick

Смежные вопросы