The expression tree uses a tree-like structure to represent the code. Each node of it is an expression, such as method calls and binary operations such as x<y. We can edit and operate the content of the expression tree, so that we can dynamically modify executable code, and create queries dynamically. We can use anonymous lambda expressions or C# API to create expression trees.
This series of articles is mainly a summary of the C# expression tree. The basic knowledge refers to the content of MSDN. This part of the content can be viewed directly on MSDN. The following articles will mainly share the part applied to the expression tree when you encounter work. Please record and share it.
Generate expression tree
Create an expression tree through lambda expression
By assigning a lambda expression to a variable of type Expression<TDelegate>, the compiler can automatically generate an expression tree that creates the lambda expression. The C# compiler can only generate an expression tree from lambda expressions, it can only be a single-line lambda expression, and it cannot parse multi-line lambda statements. As follows, you can create an expression tree of lambda expression num=>num<5 in the following way:
Expression<Func<int, bool>> lambda = num => num < 5;
Create an expression tree through the API
To create expressions using the API, you need to use the Expression class. This class contains static factory methods to create nodes of specific types of expression trees, such as the variable ParameterExpression representing parameters, and the MethodExpression representing method calls. ParameterExpression, MethodExpression, and other specific expression types are all defined in the namespace, and these types are derived from the Expression abstract class.
The following example is to use the API to create the expression tree corresponding to the lambda expression of num=>num<5:
ParameterExpression numPara = (typeof(int), "num");// Parameter numConstantExpression five = (5, typeof(int));//Constant 5 BinaryExpression numLessThanFive = (numPara, five); Expression<Func<int, bool>> lambda1 = <Func<int, bool>>(numLessThanFive, new ParameterExpression[] { numPara });
Starting from .NET Framework 4, the Expression Tree API also supports assignment and process control, such as loops, conditional blocks, try... catch blocks, etc. Compared to creating an expression tree through lambda expressions, you can use the API to create more complex expression trees, such as the following expression tree that uses the API to create a number factorial expression tree:
// Parameter valueParameterExpression value = (typeof(int), "value"); //Local variableParameterExpression result = (typeof(int), "result"); // Tags, used to jump out of loopLabelTarget label = (typeof(int)); //Create expression blockBlockExpression block = ( //Add local parameters result new[] { result }, //result=1 Assignment (result, (1)), //cycle ( //Cyclic conditions ( //If value>1 (value, (1)), //Then result*=value--; (result, (value)), //Otherwise, the loop loop will break out. Execution of statements that jump to label (label, result) ), label ) ); //Compile the expression treeFunc<int, int> factor = <Func<int, int>>(block, value).Compile(); //Execute, output result 120(factor(5));
Analyze expression tree
After getting the expression tree, how to get each part of the expression tree is very useful in some cases. The following example shows how to get the various parts of num=>num<5.
Expression<Func<int, bool>> expreTree = num => num < 5; ParameterExpression param = (ParameterExpression)[0];//num BinaryExpression operation = (BinaryExpression);//< ParameterExpression left = (ParameterExpression);//num ConstantExpression right = (ConstantExpression);//5 //output Decomposed expression: num => num LessThan 5 ("Decomposed expression:{0} = > {1} {2} {3}", , , , );
Compile expression tree
The Expression<TDelegate> type has a Compile method, which can compile the expression tree into the corresponding TDelegate delegate type, and the usage method is as follows:
// Create an expression treeExpression<Func<int, bool>> expr = num => num < 5; // Compile the expression tree into the corresponding delegateFunc<int, bool> result = (); //Call the delegate method and output True(result(4)); //You can also directly compile and call it, and output True(()(4));
For example, the following example demonstrates creating an expression tree and then compiling and executing:
//Create the execution logic of the expression treeBinaryExpression be = ((2D), (3D)); //Create an expression treeExpression<Func<double>> le = <Func<double>>(be); //Compile the expression treeFunc<double> compileExpression = (); //Execute the lambda expression and get the result 8double result = compileExpression(); (result);
Modification of expression tree
The expression tree is an immutable object, similar to string, and cannot be modified directly. It can only be copied and then reconstructed. For details, please refer to MSDNHow to modify expression trees (C#).
Conclusion
References to all contents of this articleExpression tree on MSDNIf you have basic suggestions, please read the contents directly. This is just a personal note and is also the most basic part of the expression tree. Some usages of the expression tree will be introduced later.
The above is the detailed explanation of the basic usage of C# expression tree. For more information about C# expression tree, please pay attention to my other related articles!