C # expression tree explanation (1)

I. Preface

I have always wanted to write an article about Dpper’s customized extension, but it will be designed to parse Lambda expressions, and to parse Lambda expressions, you must Know the relevant knowledge points of expression trees. I hope that by explaining more about the knowledge points or applications of each module, I can help gardeners to learn more. Although the explanation is not comprehensive, if it can be a key to open this piece, it would be more gratifying for the snail.

Second, expression tree understanding

The expression tree represents the code in a tree-shaped data structure, where each node is an expression, which we can directly write by the code. The logic of is stored in a tree-like structure in the form of expressions, so that the tree can be parsed at runtime, and then executed, to achieve dynamic editing and execution of the code. Linq to SQL in .Net is the analysis of expression trees.

Here we will first explain the expression and expression tree. I believe everyone knows that expressions, such as x+5 or 5, can be regarded as expressions, and the tree in the expression tree refers to the binary tree. It is a collection of expressions. The Expression class in C# is an expression class. For an expression tree, the leaf nodes are all parameters or constants, and the non-leaf nodes are all operators or control symbols.

2.1. Creation of expression

Lambda expression method:

Expressionint, int,bool>> fun = (x, y) => x 

The expression root node type created by this method is ExpressionType.Lambda, and the Type type is the return value type typeof(bool)

Assembly method (create expression tree through API):

ParameterExpression numParam = Expression.Parameter( typeof(int), "num");

ConstantExpression five = Expression.Constant(5, typeof(int)) ;
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expressionint, bool>> lambda1 =
Expression.Lambdaint, bool>>(
numLessThanFive,
new ParameterExpression[] {numParam });

We first created two parameter expressions num And 5, and then assembled together with LessThan, the final expression is "num<5", the node type of expr is LessThan, and the Type type is typeof(bool)

Let’s take a look at the expression tree first The structure of

First of all, the function of Expression is to express a strongly typed Lambda expression as a data structure in the form of an expression tree. Its parent class is LambdaExpression. Comparing their codes, we can see that the main body of Lambda expressions , The name and parameters are all stored in LambdaExpression.

Expression and LambdaExpression code screenshots:

image

image

The Body in LambdaExpression is our expression.

C# expression provides us with a wealth of expression classes, enter the LambdaExpression class

image

Methods whose return type ends with "Expression" are basically an expression class.

For the definition and creation method of each expression, please refer to the official Microsoft document https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.binaryexpression?view =netframework-4.8

The following are the most commonly used expressions

ConstantExpression: Constant expression

>

ParameterExpression: Parameter Expression

UnaryExpression: Unary operator expression

BinaryExpression: Binary operator expression

TypeBinaryExpression: is operator expression

ConditionalExpression: conditional expression

MemberExpression: access field or attribute expression

MethodCallExpression: Call member function expression

Expression: delegate expression

2.2. Expression analysis< /h3>

Expression tree analysis

We can know from the LambdaExpression class that the expression tree contains: parameters [Parameters], expression tree type [NodeType], expression [Body], return type [ReturnType], the delegate of the Lambda expression [Compile] and the name of the Lambda expression [name], as shown in the figure:

image

Expression analysis:

All expressions include: left node [Left], right node [Right], type [NodeType] , Different expressions will have other attributes, and the left and right nodes here are still expressions.

The image below is a screenshot of BinaryExpression expression

image

Expression tree and the type NodeType in the expression It is an enumeration, with a total of 85 types, friends who are interested can go and learn about it.

The commonly used types are as follows:

ExpressionType.And: similar to &

ExpressionType.AndAlso: C# is similar to &&

ExpressionType.Or span>: Similar in C#|

ExpressionType.OrElse: Similar in C#||

ExpressionType.Equal: Similar to ==

ExpressionType.NotEqual in C# : Similar in C#!=

ExpressionType.GreaterThan: Similar in C#>

ExpressionType.GreaterThanOrEqual: Similar to >=

ExpressionType.LessThan: C# in C# Similar to <

ExpressionType.LessThanOrEqual: similar to <=

ExpressionType.Add: similar to +

in C#

ExpressionType.AddChecked: similar to in C# +

ExpressionType.Subtract: C# is similar to -

ExpressionType.SubtractChecked: C# is similar to -

ExpressionType.Divide: C# is similar to/

ExpressionType.Multiply: C# Similar to *

ExpressionType.MultiplyChecked: similar to *

in C#

2.3, Compile expression tree< /h3>

At the expression creation, we created a Lambda expression in combination, so how should we use it? In "Expression Analysis", both LambdaExpression class and Expression class have a Compile method. The scientific name is the delegate of Lambda expression, which is actually the delegate of Lambda expression compilation function, so we only need to call it to get The result is a functional method.

The code is modified as follows:

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");

ConstantExpression five = Expression.Constant(5, typeof(int)) ;
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expressionint, bool>> lambda1 =
Expression.Lambdaint, bool>>(
numLessThanFive,
new ParameterExpression[] {numParam }); Console.WriteLine($"Lambda content: {lambda1.ToString()}"); //Expression compilation var func = lambda1.Compile(); Console.WriteLine($"Lambda operation result: {func(6)}");

Run results

image

Three. Summary

here We have done a basic explanation of expressions. I believe everyone has a preliminary understanding of Lambda expressions. Below we will continue to explain the traversal of an expression tree.

Expressionint, int< /span>,bool>> fun = (x, y) => x 

ParameterExpression numParam = Expression.Parameter(typeof(int), "num");

ConstantExpression five = Expression.Constant(5, typeof(int)) ;
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expressionint, bool>> lambda1 =
Expression.Lambdaint, bool>>(
numLessThanFive,
new ParameterExpression[] {numParam });

ParameterExpression numParam = Expression.Parameter( typeof(int), " num");

ConstantExpression five = Expression.Constant(5, typeof(int)) ;
BinaryExpression numLessThanFive = Expression.LessThan(numParam, five);
Expressionint, bool>> lambda1 =
Expression.Lambdaint, bool>>(
numLessThanFive,
new ParameterExpression[] {numParam }); Console.WriteLine($"Lambda content: {lambda1.ToString()}"); //Expression compilation var func = lambda1.Compile(); Console.WriteLine($"Lambda operation result: {func(6)}");

Leave a Comment

Your email address will not be published.