How to convert:
System.Linq.Expression.Expression
Into:
Microsoft.CodeAnalysis.CSharp.CSharpCompilation
Or into:
Microsoft.CodeAnalysis.CSharp.CSharpSyntaxTree
I need next specific cases to work like one of the options:
I can compile Expression
and CSharpSyntaxTree
to the same behavior of the executable code
When I look at C# expression typed manually then 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:
Approach Expression -> string -> Roslyn
in unacceptable. Conversion should be direct.
UPDATE2: Possible usages:
a. Faster start
b. Compile time errors, not runtime errors.
c. Possibly faster runtime.
d. Allow C# to live longer by eating F# pie.
e. Possibly more hybrid libraries, e.g. for matrix(images) manipulation which allow to copy and paste resulted tree created on Server/Desktop as code to be used on IoT.
a. More options of output of code (namespaces, spaces, tabs). b. More correctness with less manual code of generation. c. Support for different output language rather than C#.
Because the syntax trees are immutable, the Syntax API provides no direct mechanism for modifying an existing syntax tree after construction. However, the Syntax API does provide methods for producing new trees based on specified changes to existing ones. Each concrete class that derives from SyntaxNode defines With* methods which you can use to specify changes to its child properties.
Additionally, the ReplaceNode extension method can be used to replace a descendent node in a subtree. Without this method updating a node would also require manually updating its parent to point to the newly created child and repeating this process up the entire tree
- a process known as re-spining the tree.
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 it out live at: http://roslynquoter.azurewebsites.net/
The easiest way of converting Expression
to Roslyn SyntaxTree
would be:
Expression
to corresponding source code.CSharpSyntaxTree.ParseText()
.We basically reduced a problem to converting Expression
to its source code. Such question was already asked on SO. Among answers Steve Wilkes proposed his library AgileObjects.ReadableExpressions.
It basically provides one extension method ToReadableString()
on Expression
:
// str will contain source code of expression
var str = expression.ToReadableString();
I've tried this library with different expressions and it works perfectly fine.
So returning to you problem, solution based on this library will be very simple:
Define 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 could try it:
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 expression will be converted to the following code:
var p = 1;
p += 5;
which is successfully parsed to corresponding SyntaxTree
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With