Splitting the expressions with Roslyn

2019-04-16 01:26发布

I am using Roslyn and I want to split the statement as below,

string stringVariable = "string";
int intVariable = 10;
Console.Write(stringVariable + string.Concat("string1","string2") + intVariable.ToString()) 
  1. Console.Write()
  2. stringVariable
  3. string.Concat("string1","string2")
  4. intVariable.ToString()

I have asked a question and got answer for splitting the expressions Splitting the Expression statements with Roslyn but this suggestion splits the string.Concat("string1", "string2") as below,

  1. string.Concat()
  2. string1
  3. string2

But i dont want to split the inner expressions, I need to keep the inner expressions as it is. How can I do this with Roslyn?

1条回答
仙女界的扛把子
2楼-- · 2019-04-16 02:04

The expression Console.Write(stringVariable + string.Concat("string1","string2") + intVariable.ToString()) is a InvocationExpressionSyntax. The InvocationExpressionSyntax can be further splitted into expression and arguments.

Here the expression part will have Console.Write and the argument part will have stringVariable + string.Concat("string1","string2") + intVariable.ToString() .

Now the argument will be the BinaryExpressionSyntax .

We can split the BinaryExpressionSyntax by visiting the SyntaxNodes. So when Visiting we can just avoid traversing the "inner expressions" by identifyning its syntax( like InvocationExpressionSyntax, MemberAccessExpressionSyntax..etc) .

The code for visiting the Binary expression as above will be.

public class BinaryExpressionVisitor : CSharpSyntaxRewriter
{
    List<string> restrictedTokens = new List<string>();
    internal List<object> binaryExpressionNodes = new List<object>();

    public BinaryExpressionVisitor()
    {
        restrictedTokens.Add("IdentifierToken");
        restrictedTokens.Add("NumericLiteralToken");
        restrictedTokens.Add("StringLiteralToken");
    }

    public override SyntaxNode VisitBinaryExpression(BinaryExpressionSyntax node)
    {
        return base.VisitBinaryExpression(node);
    }

    public override SyntaxNode Visit(SyntaxNode node)
    {
        if (node.GetType().Name != "BinaryExpressionSyntax" && node.GetType().Name != "ParenthesizedExpressionSyntax")
            binaryExpressionNodes.Add(node);
        return base.Visit(node);
    }

    public override SyntaxToken VisitToken(SyntaxToken token)
    {
        if (!restrictedTokens.Contains(token.CSharpKind().ToString().Trim()))
            binaryExpressionNodes.Add(token);
        SyntaxToken baseToken = base.VisitToken(token);
        return baseToken;
    }

    public override SyntaxNode VisitInvocationExpression(InvocationExpressionSyntax node)
    {
        return node;//Bypassing the expression instead of base.Visit(node)
    }

    public override SyntaxToken VisitListSeparator(SyntaxToken separator)
    {
        SyntaxToken baseToken = base.VisitListSeparator(separator);
        return baseToken;
    }
}

The class can be invoked by,

BinaryExpressionVisitor expressionVisitor = new BinaryExpressionVisitor();
expressionVisitor.VisitBinaryExpression(binaryExpressions);
List<object> nodeList = expressionVisitor.binaryExpressionNodes;

The nodeList will have the below result.

  • [0] = "IdentifierNameSyntax IdentifierName stringVariable"
  • [1] = "SyntaxToken PlusToken +"
  • [2] = "InvocationExpressionSyntax InvocationExpression string.Concat(\"string1\", \"string2\")"
  • [3] = "SyntaxToken PlusToken +"
  • [4] = "InvocationExpressionSyntax InvocationExpression intVariable.ToString()"
查看更多
登录 后发表回答