C# Expression Trees: Creation, Generation, Usage, Converting Lambda to Expression Trees, Detailed Knowledge of Expression Trees

2019年12月15日 112点热度 0人点赞 1条评论
内容目录

The author recently studied the concept of expression trees and wrote this article to reinforce understanding. If there are any errors, please comment and point them out~


Concept of Expression Trees

  • The creation of expression trees can be done using Lambda method and Assembly method.
  • To learn about expression trees, one needs the foundation of Delegates, Lambda, Func<>.
  • The shape of an expression tree can reference a binary tree.

  • An expression tree can be understood as a mathematical expression.

Mathematical expression constants and symbols serve as the bottom nodes of the expression tree. Each computation generates a result which is a node, or their common node represents the operation they should perform.


Generating Expression Trees

Expression trees can be created using Lambda expression method and Assembly method.

For convenience, the expression generated here is ( i * j ) + ( x * y ).

Their computation is as follows

Generating Expression Trees with Lambda

To create an application in the console, you need to include:

using System.Linq.Expressions;

1. Create an expression

(The system automatically converts the Lambda expression into an expression tree; however, not all Lambda expressions can be converted, refer to the section “System automatically converts Lambda expressions to expression trees” at the end of the article for details).

Expression<Func<int, int, int, int, int>> func = (i, j, x, y) => (i * j) + (x * y);

2. Output the system-converted expression

After entering this line of code and running it, check the console output of the expression tree.

Console.WriteLine(func);

3. Convert code to data

(Using code as data)

var compile = func.Compile();      
            // or Func<int, int, int, int, int> compile = func.Compile();

4. Substitute numbers for computation

int result = compile(12, 13, 14, 15);       // Substitute specific numbers into the expression and compute
            Console.WriteLine(result);      // Output the expression result

The complete code is as follows:

           Expression<Func<int, int, int, int, int>> func = (i, j, x, y) => (i * j) + (x * y);
            Console.WriteLine(func);        //Output expression
        <span style="color: #0000ff;">var</span> compile = func.Compile();       <span style="color: #008000;">//</span><span style="color: #008000;">Convert code to data
        </span><span style="color: #008000;">//</span><span style="color: #008000;">or Func&lt;int, int, int, int, int&gt; compile = func.Compile();</span>

        <span style="color: #0000ff;">int</span> result = compile(<span style="color: #800080;">12</span>, <span style="color: #800080;">13</span>, <span style="color: #800080;">14</span>, <span style="color: #800080;">15</span>);       <span style="color: #008000;">//</span><span style="color: #008000;">Substitute specific numbers into the expression and compute</span>
        Console.WriteLine(result);      <span style="color: #008000;">//</span><span style="color: #008000;">Output the expression result</span>
        Console.ReadKey();</pre>

Console Output:

 

Generating Expression Trees with Assembly Method

Expressions consist of "symbols" and operators.

Use ParameterExpression type to modify parameters and instantiate parameters using Expression.Parameter(Type type, string name).

1. Generate parameters a, b, and d

                 ParameterExpression a = Expression.Parameter(typeof(int), "i");
            ParameterExpression b = Expression.Parameter(typeof(int), "j");
            ParameterExpression c = Expression.Parameter(typeof(int), "x");
            ParameterExpression d = Expression.Parameter(typeof(int), "y");

 

Analysis:

i, j, x, y are node names, a, b, c, d are instance names. There's no need to waste energy thinking about the naming conventions for a, b, c, d, i, j, x, y above.

ParameterExpression indicates creating a node, while Parameter represents a named parameter expression; for more details, please refer to the section “Classification of Expression Parameters” later in the article.

Expression.Parameter(Type type, string name) indicates the properties of this node.

2. Generate nodes

            Expression r1 = Expression.Multiply(a, b);      //Multiplication operation
            Expression r2 = Expression.Multiply(c, d);      //Multiplication operation

 

Analysis:

Two operations ( i * j ) and ( x * y ) have been created.

Multiply denotes a multiplication operation that does not perform overflow checking. The Expression class has 85 operation methods; further details on addition, subtraction, multiplication, division, and comparisons will be provided in the section “Arithmetic Operators” later in the article.

3. Generate Endpoint

Expression result = Expression.Add(r1, r2);     // Addition

4. Generate Expression Tree, Transform, Output Expression Tree, Substitute Data for Calculation

            Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);
            var com = func.Compile();
            Console.WriteLine("Expression" + func);
            Console.WriteLine(com(12, 12, 13, 13));

 

The complete code is as follows:

            ParameterExpression a = Expression.Parameter(typeof(int), "i");
            ParameterExpression b = Expression.Parameter(typeof(int), "j");
        Expression r1 </span>= Expression.Multiply(a, b);      <span style="color: #008000;">//</span><span style="color: #008000;"> Multiplication Operation</span>
        ParameterExpression c = Expression.Parameter(<span style="color: #0000ff;">typeof</span>(<span style="color: #0000ff;">int</span>), <span style="color: #800000;">"</span><span style="color: #800000;">x</span><span style="color: #800000;">"</span><span style="color: #000000;">);
        ParameterExpression d </span>= Expression.Parameter(<span style="color: #0000ff;">typeof</span>(<span style="color: #0000ff;">int</span>), <span style="color: #800000;">"</span><span style="color: #800000;">y</span><span style="color: #800000;">"</span><span style="color: #000000;">);
        Expression r2 </span>= Expression.Multiply(c, d);      <span style="color: #008000;">//</span><span style="color: #008000;"> Multiplication Operation</span>


Expression result
= Expression.Add(r1, r2); // Addition
// The above code generates nodes
// Generates Expression
Expression<Func<int, int, int, int, int>> func = Expression.Lambda<Func<int, int, int, int, int>>(result, a, b, c, d);
var com = func.Compile();
Console.WriteLine(
"Expression" + func);
Console.WriteLine(com(
12, 12, 13, 13));
Console.ReadKey();

Console Interface


 

Supplementary Notes

1. The system automatically converts Lambda expressions into expression trees

    The requirement for lambda expressions can only be represented by the input parameters and return parameters. Lambda expressions cannot contain other constructs such as conditionals or loops.

      Example of an error

            Expression<Func<int, int, int, int, int>> func = (a, b, c, d) =>
            {
                if (a < 10)
                {
                    a += 1;
                }
                /*
                 * Other operation code
                 */
                return a + b + c + d;
            };

View Code

 

      Remove all those elements, modified as follows:

 Expression<Func<int, int, int, int, int>> func = (a, b, c, d) => a + b + c + d;

  This "simplest" lambda expression can be automatically converted into an expression tree by the system.

2. Arithmetic Operators

     In general mathematics, there are operations such as addition, subtraction, multiplication, division, modulus, and exponentiation, while in programming, there are more options for arithmetic operators, reaching 85 types.

      The author provides a diagram listing some methods.

Official list of arithmetic operators by Microsoft https://docs.microsoft.com/zh-cn/dotnet/api/system.linq.expressions.expression?view=netframework-4-7-2

It is estimated that everyone may find Microsoft's documentation a bit unsatisfactory~ Here is a recommended list translated and organized by a great expert https://blog.csdn.net/zhuqinfeng/article/details/70168337

3. Expression Parameters

Using the mathematical ellipse perimeter formula: L = 2πb + 4(a-b) , where a is the length of the semi-major axis and b is the length of the semi-minor axis, for example:

Parameter is similar to an unknown in mathematics, such as a, b; methods of use:

ParameterExpression a = Expression.Parameter(typeof(int), "a")
ParameterExpression b = Expression.Parameter(typeof(int), "b")

Constant represents a constant, for example in 2πb, it can be 2 or 2π; methods of use:

ConstantExpression define = Expression.Constant(2);

For more classifications of parameters, please refer to https://blog.csdn.net/zhuqinfeng/article/details/70168337

Here is a part of the captured image:

4. Methods for Operations in Expression

Methods representing operations such as addition, subtraction, multiplication, and division. The following diagram illustrates this:

Multiply(a,b) denotes multiplication, while Add(r1,r2)  denotes addition.

Of course, it’s not that simple; they all have related overloaded methods and advanced uses.

For more information, please check https://blog.csdn.net/zhuqinfeng/article/details/70168337

Here are some screenshots:

 5. Advanced Uses of Expression Trees

Expression trees can be combined with database queries or LINQ, deriving many advanced operations.

For example, dynamic querying, traversing expression trees, converting to a SQL WHERE clause, etc. Due to space constraints, the author will not elaborate further.

You can view all types of objects in System.Linq.Expressions at the following link:

https://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions?view=netframework-4.7.2

Study hard and make progress every day~ Hope to succeed in the interview on the 3rd.

痴者工良

高级程序员劝退师

文章评论