C#表达式树
λ表达式树、lambda、委托它们之间的区别和联系
委托是一种类型,是方法的抽象,通过委托可以将方法以参数的形式传递给另一个方法
,同时调用委托的时候,它所包含的方法都会被实现。委托的关键字是delegate,可以自定义委托,也可以使用内置委托Func、Action,通过简化,可以将Lambda表达式或Lambda语句赋值给委托,委托的调用包括同步调用和异步调用。表达式树(Expression)
是一种数据结构,表达式树也称表达式目录树,是将代码以一种抽象的方式表示成一个对象树,树中每个节点本身都是一个表达式。表达式树不是可执行代码,它是一种数据结构。可以利用Lambda表达式进行声明,Lambda表达式的规则要符合Expression中Func委托的参数规则,但Lambda语句是不能声明的。lambda是当委托只有一句话代码的时候的最简写形式。
Lambda表达式不仅可以用来创建委托实例,C#编译器也能够将他们转换成表达式树。
1 | //Func委托,必须要有返回值,最后一个参数为返回值,前面为输入参数 |
常用的linq和EFCore也是使用的委托和表达式树1
2
3
4
5new List<int>().AsQueryable().Where(s => s == 1);//使用表达式树
public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
new List<int>().Where(s => s == 1);//使用委托
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
λ表达式树入门
常见Expression API
1 | Expression.Add, Expression.Subtract, Expression.Multiply, Expression.Divide:二元数学操作符。 |
例
(a,b)=>a3+b4
1 | var a = Expression.Parameter(typeof(int), "a");//声明一个int类型的参数a |
1 | 结果: |
替代反射
测试类
1 | public class MyClass |
创建实例
1 | var newExpression = Expression.New(typeof(MyClass).GetConstructor(new[] { typeof(int) }), Expression.Constant(100)); // 有参构造函数方式 |
获取属性值
e=>e.MyProperty 使用 Expression.Property
e=>e.MyProperty表达式分析得到两部分:参数和属性,也是一种基本表达式
1 | var e = Expression.Parameter(typeof(MyClass), "e"); |
1 | 结果: |
为属性赋值
例: e=>e.MyProperty=new List
e=>e.List=new List
1 | var newExpression = Expression.New(typeof(MyClass).GetConstructor(new[] { typeof(int) }), Expression.Constant(100));// 有参构造函数方式 |
1 | 结果: |
调用无参方法
调用方法通过Expression.Call进行对象的方法调用,调用前需要先获取被调用的方法对象
1 | var e = Expression.Parameter(typeof(MyClass), "e"); |
1 | 结果: |
调用有参方法
1 | var e = Expression.Parameter(typeof(MyClass), "e"); |
调用linq拓展方法

1 | var e = Expression.Parameter(typeof(MyClass), "e"); |
1 | 结果: |
条件表达式
Expression.Condition,即可生成三目表达式的λ表达式树1
2
3
4var x = Expression.Parameter(typeof(int), "x");
var gt60 = Expression.GreaterThan(x, Expression.Constant(60));//x>60
var condition = Expression.Condition(gt60, Expression.Constant("及格"), Expression.Constant("不及格"));//x>60?"及格":"不及格"
var lambda = Expression.Lambda<Func<int, string>>(condition, x);//x=>x>60?"及格":"不及格"
null值表达式
e=>e.MyProperty??”s”
Expression.Coalesce便是对标的C#6专属的null值表达式
1 | var e = Expression.Parameter(typeof(MyClass), "e"); |
类型转换
Convert.ToInt32(x)
Expression.Convert即等价于Convert静态类
1 | var convert = Expression.Convert(Expression.Constant(10.234), typeof(int)); |
声明一个数组对象
Expression.NewArrayBounds即可生成一个创建数组对象的表达式:
1 | var array = Expression.NewArrayBounds(typeof(string), Expression.Constant(5)); |
实战
m=>m.MyProperty.Contains(“ldqk”)||m.List.Any(s=>s.Length>1&&s.Contains(“a”))1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20// 前一部分
var m = Expression.Parameter(typeof(MyClass), "m");
var myProperty = Expression.Property(m, nameof(MyClass.MyProperty)); // m.MyProperty
var contains = Expression.Call(myProperty, typeof(string).GetMethod("Contains", new[] { typeof(string) }),
Expression.Constant("ldqk")); // m.MyProperty.Contains("ldqk")
//后一部分
var s = Expression.Parameter(typeof(string), "s");
var length = Expression.Property(s, nameof(string.Length)); //s.Length
var gt10 = Expression.GreaterThan(length, Expression.Constant(1)); //s=>s.Length>1
var anyConstains = Expression.Call(s,typeof(string).GetMethod("Contains", new[] { typeof(string) }), Expression.Constant("a"));// s.Contains("a")
var anyWhere = Expression.And(gt10, anyConstains); //s.Length>1&&s.Contains("a")
var anyLambda = Expression.Lambda(anyWhere, s);
var any = typeof(Enumerable).GetMethods().FirstOrDefault(info => info.GetParameters().Length == 2 && info.Name == "Any").MakeGenericMethod(typeof(string));
var list = Expression.Property(m, nameof(MyClass.List)); // m.List
var whereLambda = Expression.Call(null, any, list, anyLambda);
var lambda = Expression.Lambda<Func<MyClass, bool>>(Expression.OrElse(contains, whereLambda),m); //m=>m.MyProperty.Contains("ldqk")||m.List.Any(s=>s.Length>1&&s.Contains("a"))
Console.WriteLine(lambda);
链式调用s=>s.List.Select(e => e.Length).OrderBy(x=>x).FirstOrDefault() > 11
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21var s = Expression.Parameter(typeof(MyClass), "s");
var list = Expression.Property(s, nameof(MyClass.List)); //s.List
var selectMethod = typeof(Enumerable).GetMethods()
.FirstOrDefault(info => info.GetParameters().Length == 2 && info.Name == "Select")
.MakeGenericMethod(typeof(string), typeof(int));
var e = Expression.Parameter(typeof(string), "e");
var elen = Expression.Property(e, nameof(string.Length)); // e.Length
var selectLambda = Expression.Lambda<Func<string, int>>(elen, e); // e=>e.Length
var select = Expression.Call(selectMethod, list, selectLambda);//s.List.Select(e => e.Length)
var orderby = typeof(Enumerable).GetMethods().FirstOrDefault(info => info.GetParameters().Length == 2 && info.Name == "OrderBy").MakeGenericMethod(typeof(int), typeof(int));
var parameter = Expression.Parameter(typeof(int), "x");
var orderbyLambda = Expression.Lambda(parameter, parameter); //x=>x
var orderByCall = Expression.Call(orderby, select, orderbyLambda); //s.List.Select(e => e.Length).OrderBy(x=>x)
var first = typeof(Enumerable).GetMethods().FirstOrDefault(info => info.GetParameters().Length == 1 && info.Name == "FirstOrDefault").MakeGenericMethod(typeof(int));
var firstExp = Expression.Call(null, first, orderByCall); //s.List.Select(e => e.Length).OrderBy(x=>x).FirstOrDefault()
var greaterThan = Expression.GreaterThan(firstExp, Expression.Constant(1)); //s.List.Select(e => e.Length).OrderBy(x=>x).FirstOrDefault() > 1
var lambda = Expression.Lambda<Func<MyClass, bool>>(greaterThan, s);
Console.WriteLine(lambda);






