Expression trees can be said to be one of the core of LINQ, and why is it one of the core of LINQ? Because the expression tree allows C # to no longer just compile into IL, we can generate an expression tree from C #, using the result as an intermediate format, to convert it to the native language on the target platform. such as SQL. This is how LINQ to SQL is used to generate SQL.
The expression tree, introduced after. NET 3.5, is a powerful and flexible tool (such as constructing dynamic Queries in LINQ).
First look at the API interface of expression class:
namespacesystem.linq.expressions{// //Summary://A strongly typed lambda expression is represented as a data structure in the form of an expression tree. This class cannot be inherited. // //type parameter://tdelegate://System.Linq.Expressions.Expression ' 1 represents the type of delegate. Public Sealed classExpression<tdelegate>: lambdaexpression {// //Summary://compiles the lambda expression described by the expression tree into executable code and generates a delegate that represents the lambda expression. // //return Result://a delegate of type TDelegate that represents the compiled lambda expression described by System.Linq.Expressions.Expression ' 1. Publictdelegate Compile (); // //Summary://generates a delegate that represents a lambda expression. // //Parameters://Debuginfogenerator://the debug information generator used by the compiler to mark sequence points and annotate local variables. // //return Result://The delegate that contains the compiled version of the lambda. Publictdelegate Compile (Debuginfogenerator debuginfogenerator); // //Summary://creates a new expression that is similar to this expression, but uses the provided children. If all children are the same, this expression is returned. // //Parameters://Body://the System.Linq.Expressions.LambdaExpression.Body property of the result. // //Parameters://the System.Linq.Expressions.LambdaExpression.Parameters property of the result. // //return Result://this expression, if no children have been changed, or an expression with an updated child. PublicExpression<tdelegate> Update (Expression body, ienumerable<parameterexpression>parameters); protected Internal OverrideExpression Accept (ExpressionVisitor visitor); }}
The syntax for an expression tree is as follows:
expression<func<type,returntype>> = (param) = = lamdaexpresion;
For example:
expression<func<intint int >> expr = (x, y) = = X+y;
We run the above code and look at this expression tree in vs Debug mode:
You can see that the expression tree consists mainly of the following four parts:
1, Body body part
2. Parameters parameter part
3. NodeType node type
4. Lambda expression type
In the preceding code, the body is: X+y, the parameter is (x, y), NodeType is a lambda expression, and the return value is int
The body part can be an expression, but it cannot contain statements. For example: I define a delegate that a lambda expression can write
func<intint int > func = (x, y) + x + y;
You can also write this:
func<intint intreturn x + y; };
However, in an expression tree, you can only use the first notation if you compile a report error using the second notation: you cannot convert a lambda expression with a statement body to an expression tree.
In addition to the above notation, the expression tree can also be written like this:
ParameterExpression pex1 = Expression.parameter (typeof(int),"x");//first parameterParameterExpression pex2 = Expression.parameter (typeof(int),"y");//a second parameterbinaryexpression bexp= Expression.add (Pex1, PEX2);//additionvarLambdaexp = expression.lambda<func<int,int,int>> (Bexp,NewParameterexpression[] {pex1,pex2});
VS Debug Mode You can see that the two types of expressions generated by the expression tree are the same
Compiling an expression tree into a delegate
LambdaExpression is a type derived from expression. The generic class expression<tdelegate> is derived from LambdaExpression, where the generic parameter tdelegate must be a delegate type.
LambdaExpression has a compile method to create a delegate of the appropriate type. The expression<tdelegate> compile method returns a delegate of type TDelegate. Take a look at the following example:
expression<func<int,int,int>> expr = (x, y) + x +y; ParameterExpression Pex1= Expression.parameter (typeof(int),"x");//first parameterParameterExpression pex2 = Expression.parameter (typeof(int),"y");//a second parameterbinaryexpression bexp= Expression.add (Pex1, PEX2);//Body, addition//use the Expression.lambda method to create an expression of a delegate type knownexpression<func<int,int,int>>Lambdaexp= expression.lambda<func<int,int,int>> (Bexp,Newparameterexpression[] {pex1, pex2}); Func<int,int,int> tdelegate = Lambdaexp.compile ();//Compile as DelegateConsole.WriteLine (TDelegate (1,3)); Console.read ();
We run the above code with the result: 4. We wrote a lot of code, essentially using expression trees to calculate the results of 1+3.
Shallow solutions to expression trees in C #