How to convert an expression to CSharpCompilation or CSharpSyntaxTree?

How to convert:

System.Linq.Expression.Expression 

IN:

 Microsoft.CodeAnalysis.CSharp.CSharpCompilation 

Or in:

 Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree 

I need the following specific cases to work as one of the parameters:

  • I can compile Expression and CSharpSyntaxTree to the same executable code behavior

  • When I look at the C # expression entered manually, I can get CSharpSyntaxTree and it will generate the same code.

     public void MultipleStatementsBlockTest() { var p = Expression.Parameter(typeof(int), "p"); Expression assignment = Expression.Assign(p, Expression.Constant(1)); Expression addAssignment = Expression.AddAssign(p, Expression.Constant(5)); // Convert addAssignment to Roslyn tree here } class HasIndexers { public object this[string s] => null; public object this[int i] => null; } public void CanPrettyPrintVariousIndexers() { Expression<Func<Bool>> expr = () => new HasIndexers()[3] == new HasIndexers()["three"]; // Convert expr to Roslyn tree here } 

UPDATE:

The Expression -> string -> Roslyn approach Expression -> string -> Roslyn not acceptable. The conversion must be direct.

+8
c # roslyn
source share
2 answers

See here for syntax conversion

Because the syntax trees are immutable, the Syntax API does not provide a direct mechanism for modifying an existing syntax tree after construction. However, the syntax API provides methods for creating new trees based on specified changes for existing ones. Each concrete class derived from SyntaxNode defines * methods that can be used to indicate changes to its child properties.

In addition, the ReplaceNode extension method can be used to replace a child node in a subtree. Without this method, updating the node would also require manually updating the parent to point to the newly created child and repeat this process throughout the tree

  • a process called tree rotation.

Example - Transformations using the With * and ReplaceNode methods:

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory; namespace ConstructionCS { class Program { static void Main(string[] args) { NameSyntax name = IdentifierName("System"); name = QualifiedName(name, IdentifierName("Collections")); name = QualifiedName(name, IdentifierName("Generic")); SyntaxTree tree = CSharpSyntaxTree.ParseText( @"using System; using System.Collections; using System.Linq; using System.Text; namespace HelloWorld { class Program { static void Main(string[] args) { Console.WriteLine(""Hello, World!""); } } }"); var root = (CompilationUnitSyntax)tree.GetRoot(); var oldUsing = root.Usings[1]; var newUsing = oldUsing.WithName(name); root = root.ReplaceNode(oldUsing, newUsing); } } } 

Try living at: http://roslynquoter.azurewebsites.net/

+3
source share

The easiest way to convert Expression to Roslyn SyntaxTree :

  • Convert Expression to the appropriate source code.
  • Correct the source code of an expression using CSharpSyntaxTree.ParseText() .

We basically reduced the problem to converting Expression to source code. Such a question has already been asked on SO. Among the answers, Steve Wilkes proposed his library of AgileObjects.ReadableExpressions. It basically provides one method of extending ToReadableString() on Expression :

 // str will contain source code of expression var str = expression.ToReadableString(); 

I tried this library with different expressions and it works great.

Therefore, returning to you, a solution based on this library will be very simple:

  • Install the AgileObjects.ReadableExpressions NuGet package.
  • Define the following extension method on Expression :

     public static class ExpressionExtensions { public static SyntaxTree ToSyntaxTree(this Expression expression) { var expressionCode = expression.ToReadableString(); return CSharpSyntaxTree.ParseText(expressionCode); } } 

Now you can try:

 var p = Expression.Parameter(typeof(int), "p"); Expression assignment = Expression.Assign(p, Expression.Constant(1)); Expression addAssignment = Expression.AddAssign(p, Expression.Constant(5)); BlockExpression addAssignmentBlock = Expression.Block( new ParameterExpression[] { p }, assignment, addAssignment); SyntaxTree tree = addAssignmentBlock.ToSyntaxTree(); 

Such an expression will be converted to the following code:

 var p = 1; p += 5; 

which successfully understands the corresponding SyntaxTree .

+2
source share

All Articles