Home>

table of Contents

Introduction lambda expressions create expression trees api create expression tree Parse expression tree Permanence of expression trees Compile expression tree Execute expression tree Modify the expression tree debugging

Introduction

Expression trees represent code in a tree-like data structure,Each of these nodes is an expression,Examples include method calls and binary operations such as x<y.

You can edit and manipulate the code in the expression tree.This enables dynamic modification of executable code, execution of linq queries in different databases, and creation of dynamic queries.

Expression trees can also be used in the dynamic language runtime (dlr) to provide interoperability between dynamic languages ​​and the .net framework.

First, create a lambda expression expression tree

If a lambda expression is assigned toexpression<tdelegate>Variable of type,The compiler can emit code to create an expression tree representing the lambda expression.

The c#compiler can only generate expression trees from expression lambdas (or single-line lambdas).

The following code example uses the keyword expression to create a lambda expression:

expression<action<int>actionexpression=n =>console.writeline (n);
 expression<func<int, bool>>funcexpression1=(n) =>n<0;
 expression<func<int, int, bool>>funcexpression2=(n, m) =>n-m == 0;

Second, the api creates an expression tree

Creating an expression tree via api requiresexpressionclass

The following code example shows how to create a lambda expression via api:num =>num == 0

//Create expression tree through expression class
 //lambda:num =>num == 0
 parameterexpression pexpression=expression.parameter (typeof (int));//parameter:num
 constantexpression cexpression=expression.constant (0);//Constant:0
 binaryexpression bexpression=expression.makebinary (expressiontype.equal, pexpression, cexpression);//expression:num == 0
 expression<func<int, bool>>lambda=expression.lambda<func<int, bool>>(bexpression, pexpression);//lambda expression:num =>num == 0

Code useexpressionClass static methods are created.

Parsing expression trees

The following code example shows how to decompose an expression tree representing a lambda expression num =>num == 0.

expression<func<int, bool>>funcexpression=num =>num == 0;
 //Start parsing
 parameterexpression pexpression=funcexpression.parameters [0];//lambda expression parameters
 binaryexpression body=(binaryexpression) funcexpression.body;//lambda expression body:num == 0
 console.writeline ($"Parse:{pexpression.name} =>{body.left} {body.nodetype} {body.right}");

Fourth, the expression tree is permanent

The expression tree should be permanent (like a string). This means that if i want to modify an expression tree,You must copy the expression tree and replace its nodes to create a new expression tree. You can use expression tree visitors to traverse existing expression trees.Section 7 explains how to modify the expression tree.

Five, compile expression tree

expression<tdelegate>Type providescompileMethod to compile the code represented by the expression tree into an executable delegate.

//Create expression tree
 expression<func<string, int>>funcexpression=msg =>msg.length;
 //The expression tree is compiled into a delegate
 var lambda=funcexpression.compile ();
 //call delegate
 console.writeline (lambda ("hello, world!"));
 //Simplified syntax
 console.writeline (funcexpression.compile () ("hello, world!"));

Six, execute the expression tree

Executing an expression tree may return a value,It is also possible to perform only one operation (such as calling a method).

Only expression trees that represent lambda expressions can be executed.The expression tree representing the lambda expression belongs tolambdaexpressionOrexpression<tdelegate>Types of. To execute these expression trees,Need to callcompileMethod to create an executable delegate,Then call the delegate.

const int n=1;
 const int m=2;
 //expression tree to be executed
 binaryexpression bexpression=expression.add (expression.constant (n), expression.constant (m));
 //Create a lambda expression
 expression<func<int>>funcexpression=expression.lambda<func<int>(bexpression);
 //Compile the lambda expression
 func<int>func=funcexpression.compile ();
 //Execute the lambda expression
 console.writeline ($"{n} + {m}={func ()}");

Seven, modify the expression tree

The class inheritsexpressionvisitorClass, indirect call of visitbinary method by visit method to replace!=With ==. Base class methods construct nodes similar to the passed expression tree,But these nodes replace their subtree with an expression tree recursively generated by the accessor.

internal class program
 {
 private static void main (string [] args)
 {
 expression<func<int, bool>>funcexpression=num =>num == 0;
 console.writeline ($"source:{funcexpression}");
 var visitor=new notequalexpressionvisitor ();
 var expression=visitor.visit (funcexpression);
 console.writeline ($"modify:{expression}");
 console.read ();
 }
 ///<summary>
 ///unequal expression tree accessor
 ///</summary>
 public class notequalexpressionvisitor:expressionvisitor
 {
 public expression visit (binaryexpression node)
 {
 return visitbinary (node);
 }
 protected override expression visitbinary (binaryexpression node)
 {
 return node.nodetype == expressiontype.equal
  ?expression.makebinary (expressiontype.notequal, node.left, node.right) //Remake an expression:use!=Instead of ==
  :base.visitbinary (node);
 }
 }
 }

Eight, commissioning

8.1 Parameter expressions

parameterexpression pexpression1=expression.parameter (typeof (string));
 parameterexpression pexpression2=expression.parameter (typeof (string), "msg");

Figure 8-1

Figure 8-2

From debugview, if the parameter has no name,It will be assigned an automatically generated name.

const int num1=250;
 const float num2=250;
 constantexpression cexpression1=expression.constant (num1);
 constantexpression cexpression2=expression.constant (num2);

Figure 8-3

Figure 8-4

From debugview, float has an suffix f compared to int.

expression lambda1=expression.lambda<func<int>(expression.constant (250));
 expression lambda2=expression.lambda<func<int>>(expression.constant (250), "customname", null);

Figure 8-5

Figure 8-6

Observe debugview if the lambda expression has no name,It will be assigned an automatically generated name.

c
  • Previous Windows Server2008 R2 MVC Environment Installation and Configuration Tutorial
  • Next Android custom control implements the bottom menu (top)