一:什么是表达式树

Expression我们称为是表达式树,是一种数据结构体,用于存储需要计算,运算的一种结构,这种结构可以只是存储,而不进行运算。通常表达式目录树是配合Lambda一起来使用的,lambda可以是匿名方法,当然也可以使用Expression来动态的创建!下面我们举例来说明什么是表达式目录树。

先创建一个People的实体,下面会用到

/// <summary>
/// 实体类
/// </summary>
public class People
{
    public int Age { get; set; }
    public string Name { get; set; }
    public int Id;
}

我们可以通过下面创建表达式目录树,我们称之为A种方式:

Expression<Func<People, bool>> lambda = x => x.Id.ToString().IndexOf("5") >= 0;

我们还可以使用Expression来动态创建,我们称之为B种方式:

var peopleParam = Expression.Parameter(typeof(People), "x");//创建一个x,类型为people
//得到x.Id
MemberExpression idParam = Expression.Field(peopleParam, "Id");

//得到ToString方法
MethodInfo toStringWay = typeof(int).GetMethod("ToString", new Type[] { });

//得到IndexOf的方法,然后new Type[]这个代表是得到参数为string的一个方法
MethodInfo indexOfWay = typeof(string).GetMethod("IndexOf", new Type[] { typeof(string) });

//通过下面方法得到x.Id.ToString()
MethodCallExpression tostringResult = Expression.Call(idParam, toStringWay, new Expression[] { });

//通过下面方法得到x.Id.ToString().IndexOf("5") ,MethodCallExpression继承于Expression
MethodCallExpression indexOfResult = Expression.Call(tostringResult, indexOfWay, new Expression[] { Expression.Constant("5") });

//x.Id.ToString().IndexOf("5")>=0
var lambdaBody = Expression.GreaterThanOrEqual(indexOfResult, Expression.Constant(0));

//得到x => x.Id.ToString().IndexOf("5") >= 0,后面的一个参数指的是x,如果有多个则指定多个
Expression<Func<People,bool>> lambdaResult = Expression.Lambda<Func<People, bool>>(lambdaBody, new ParameterExpression[]
                                                                                                { peopleParam });

//通过lambdaResult.Compile()得到Func<People,bool>这样的委托,然后Invoke是调用委托
bool result = lambdaResult.Compile().Invoke(new People() { Id = 155 });

A种和B种得到的结果是一致的,只不过第一种是通过lambda匿名方法来构建,第二种是通过动态的Expression来构建。另外下面的原理也是一样的

//普通的Lambda表达式
 Func<int,int,int> func = (x,y)=>  x + y - 2;
//表达式目录树的Lambda表达式声明方式
Expression<Func<int, int, int>> expression = (x, y) => x + y - 2;   
//表达式目录树的拼接方式实现 ParameterExpression parameterx = Expression.Parameter(typeof(int), "x"); ParameterExpression parametery = Expression.Parameter(typeof(int), "y"); ConstantExpression constantExpression = Expression.Constant(2, typeof(int)); BinaryExpression binaryAdd = Expression.Add(parameterx, parametery); BinaryExpression binarySubtract = Expression.Subtract(binaryAdd, constantExpression); Expression<Func<int, int, int>> expressionMosaic = Expression.Lambda<Func<int, int, int>>(binarySubtract, new ParameterExpression[] { parameterx, parametery });
int ResultLambda = func(5, 2); int ResultExpression = expression.Compile()(5, 2); int ResultMosaic = expressionMosaic.Compile()(5, 2); Console.WriteLine($"func:{ResultLambda}"); Console.WriteLine($"expression:{ResultExpression}"); Console.WriteLine($"expressionMosaic:{ResultMosaic}");

下面举例说明以下Expression.Block

ParameterExpression varExpr = Expression.Variable(typeof(int), "x"); //add(int x);
var ex1 = Expression.Assign(varExpr, Expression.Constant(1)); //x = 1; var ex1 = x;
var ex2 = Expression.Add(ex1, Expression.Constant(5)); //var ex2 = ex1 + 5;//6
var ex4 = Expression.Add(ex2, Expression.Constant(9)); //var ex4 = ex2 + 9; //15
var ex5 = Expression.Add(ex4, Expression.Constant(8)); // var ex5 = ex4 + 8; //23
BlockExpression blockExpr = Expression.Block(
    new ParameterExpression[] { varExpr },
    ex1,
    ex2,
    ex4,
    ex5
);

该代码等效于,返回的结果都以最后一个Expression为主,则为ex5这个表达式

public int add(int x)
{
    x = 1;
    var ex1 = x;
    var ex2 = ex1 + 5;//6
    var ex4 = ex2 + 9; //15
    var ex5 = ex4 + 8; //23
    return ex5; //23
}

 Expression.Block没有返回值

{   
    Expression A = Expression.Constant("第一大");
    Expression B = Expression.Constant("第二大");
    Expression ex = Expression.GreaterThan(Expression.Constant(1), Expression.Constant(2));

    var method = typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
    var AM = Expression.Call(method, A);
    var BM = Expression.Call(method, B);

    var condition = Expression.IfThenElse(ex, AM, BM);
    var blockExpr = Expression.Block(condition); //IfThenElse是没有返回值的

    foreach (var expr in blockExpr.Expressions)
        Console.WriteLine(expr.ToString());

    var lambdaExpression = Expression.Lambda<Action>(blockExpr).Compile();
    lambdaExpression();
}

 

下图是Expression的一些变量

表达式目录树(Expression)

 

二:表达式目录树与委托

Expression一般都是都是配合委托一起来使用的,比如和委托Action(没有返回值),Func(至少有一个返回参数,且最后一个值为返回参数),Action,Func既可以直接传入一个与之匹配的实体方法,又可以传入lambda表达式这种匿名类(这种是声明lambda表达式的一种快捷方式)。Expression,Action,Func关键词是在.net 3.5之后出现的。Expression<Func<>>是可以转成Func的(通过compile()这个方法转换)。反过来则不行。我们可以理解为Func<>经过定义后,就无法改变它了。而表达式树(Expression<Func<>>则是可以进行变更的。Lambda

使用lambda表达声明表达式目录树的时候注意不能有{},即:

Func<int, int, int> func = (m, n) => m * n + 2;

上面这样是可以的。但是下面这样是不被允许的:

 Expression<Func<int, int, int>> exp1 = (m, n) =>
  {
          return m * n + 2;
  };//不能有语句体   只能是一行,不能有大括号

 

下面的例子来解析一下委托和表达式目录树

 1  #region PrivateMethod
 2  private static void Do1(Func<People, bool> func)
 3  {
 4      List<People> people = new List<People>();
 5      people.Where(func);
 6  }
 7  private static void Do1(Expression<Func<People, bool>> func)
 8  {
 9      List<People> people = new List<People>()
10      {
11          new People(){Id=4,Name="123",Age=4},
12          new People(){Id=5,Name="234",Age=5},
13          new People(){Id=6,Name="345",Age=6},
14      };
15 
16      List<People> peopleList = people.Where(func.Compile()).ToList();
17  }
18 
19  private static IQueryable<People> GetQueryable(Expression<Func<People, bool>> func)
20  {
21      List<People> people = new List<People>()
22      {
23          new People(){Id=4,Name="123",Age=4},
24          new People(){Id=5,Name="234",Age=5},
25          new People(){Id=6,Name="345",Age=6},
26      };
27 
28      return people.AsQueryable<People>().Where(func);
29  }
30  #endregion
View Code

相关文章: