这里有两段代码:
看一下 Where 的参数
Linq To object 的 where 方法需要的参数是 委托
Linq To Sql的 where 方法需要的参数 是被 Expression 包裹的 委托
到这里 Lamada 表达式, 不一定是 匿名函数了,还有可能是数据结构
而且在 Lamada 表达式 作为 数据结构时 和作为匿名函数时是有区别的:
作为 数据结构的Lamada 表达式与普通表达式的区别 : 只有一行,不能有大括号 和 return
表达式目录树是可以转为委托的, 可以使用 Compile 方法 如下代码:
// 这里的Lamada 表达式是一个数据结构
// Lamada就像声明了多个变量以及变量之间的操作关系,需要的时候还可以解开
Expression<Func<int, int, int>> exp = (x, y) => x * y + 2; //正常
//作为 数据结构的Lamada 表达式与普通表达式的区别 : 只有一行,不能有大括号 和 return
Expression<Func<int, int, int>> exp1 = (x, y) => { return x * y + 2; }; //报错
//表达式目录树 转委托:
exp.Compile().Invoke(78, 78);
其实 用 Lamada 表达式 声明 表达式目录树 是一种快捷方式 ,常规的声明如下:
最简版:2+5
// 快捷
Expression<Func<int>> exp2 = () => 2 + 544;
// 常规
ConstantExpression right = Expression.Constant(2); // 声明常量
ConstantExpression left = Expression.Constant(544);// 声明常量
BinaryExpression plus = Expression.Add(left, right);// 声明运算关系
//构建表达式目录树 ,后面 的 ParameterExpression[] 为空表示参数为空
Expression<Func<int>> express = Expression.Lambda<Func<int>>(plus,new ParameterExpression[]{ });
复杂一点:
以上面的快捷方式为目的拼接:
代码:
Expression<Func<int, int, int>> exp = (x, y) => x * y +x+y+ 2; //快捷方式
//声明参数与常量
var param1 = Expression.Parameter(typeof(int), "x");
var param2 = Expression.Parameter(typeof(int), "y");
var constant = Expression.Constant(2);
//创造关系
var multiply = Expression.Multiply(param1, param2);
var plus = Expression.Multiply(multiply, param1);
var plus1 = Expression.Multiply(plus, param2);
var plus2 = Expression.Multiply(plus1, constant);
//构建表达式目录树
Expression<Func<int, int, int>> exp1 = Expression.Lambda<Func<int, int, int>>
(plus2, new ParameterExpression[] { param1, param2 });
//转换为委托并执行
Console.WriteLine(exp1.Compile().Invoke(456, 123));
Console.Read();
以上都是加减乘除的 表达式目录树 在 Linq To Sql 应用中经常是如下格式的或者更复杂:
上面的是目标 表达式目录树的 以下我们自己实现:
代码:
//普通声明
ParameterExpression x = Expression.Parameter(typeof(Company), "x");
ConstantExpression constant = Expression.Constant("3");
PropertyInfo IdProp = typeof(Company).GetProperty("Id");//Id 属性
Expression IdExp = Expression.Property(x, IdProp); //获取x与Id的关系
MethodInfo toString = typeof(int).GetMethod("ToString",new Type[] { }); //获取 ToString 方法
Expression ToStringExp = Expression.Call(IdExp, toString); //获取Id与 ToString 的关系
MethodInfo equals = typeof(string).GetMethod("Equals",new Type[] { typeof(string) }); //获取Equals
Expression EqualsExp = Expression.Call(ToStringExp, equals, new Expression[] { constant }); //获取 string 与 Equals 的关系
Expression<Func<Company, bool>> exp1 = Expression.Lambda<Func<Company, bool>>(EqualsExp, x); //建立表达式目录树
var res = exp1.Compile()(new Company() { Id = 5, Name = "王麻子" });//从表达式目录树中获取委托
我们自己手写 表达式目录树的目的是什么?这么累的玩意
为了实现动态
看一下远古拔版本的拼接条件:
到了 Linq To Sql 时代,再看看表达式目录树怎么拼接:这里的 exp 下面的会覆盖上面的,没有办法 做到 && 的结果,如果一一列举各种情况那会很累
还有第二种方案:这种方案会一直暴露 dbset 即 Company 表 很容易发生可怕的事,这是不知道怎么拼装,无奈的做法
所有我们需要让 表达式目录树 有 Or 和 And
And的初步实现:
//目标
// Expression<Func<Company, bool>> exp = x => x.Name.Equals("Qal") && x.Id > 5;
//声明参数与常量
ParameterExpression x = Expression.Parameter(typeof(Company),"x");
ConstantExpression constant = Expression.Constant("Qal");
ConstantExpression int5 = Expression.Constant(5);
//x.Name.Equals("Qal")
PropertyInfo NameProp = typeof(Company).GetProperty("Name");
var NameExp = Expression.Property(x, NameProp);
MethodInfo equals = typeof(string).GetMethod("Equals");
var equalsExp = Expression.Call(NameExp, equals, constant);
//x.Id > 5;
PropertyInfo IdProp = typeof(Company).GetProperty("Id");
var IdExp = Expression.Property(x, IdProp);
var GreaterThenExp = Expression.GreaterThan(IdExp,int5);
var body = Expression.AndAlso(equalsExp, GreaterThenExp);// 拼接两个条件的表达式目录树
// 构建表达式目录树
Expression<Func<Company, bool>> exp1 = Expression.Lambda<Func<Company, bool>>(body, new ParameterExpression[] {x});
exp1.Compile()(new Company() {Id =10,Name= "Qal" });
以上没有填完的坑待续....................