了解C#的Expression
时间:2021-12-13 作者:ryzen
我们书接上文,我们在了解LINQ下面有说到在本地查询IEnumerbale主要是用委托来作为传参,而解析型查询
IQueryable则用Expression来作为传参:
public static IEnumerable<T> Where<T>(this IEnumerable<T> enumable, Func<T, bool> func)
public static IQueryable<T> Where<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> func)
那么我们就来聊聊有关表达式Expression里面的东西吧
Expression与Expression Tree
首先我们来写下一些代码:
Expression<Func<int, int>> expression = (num) => num + 5;
域名eLine($"NodeType:{域名Type}");
域名eLine($"Body:{域名}");
域名eLine($"Body Type: {域名ype()}");
域名eLine($"Body NodeType: {域名Type}");
输出如下:
NodeType:Lambda
Body:(num + 5)
Body Type: 域名域名leBinaryExpression
Body NodeType: Add
我们将expression
转为LambdaExpression
看看都有啥:
if (域名Type == 域名da)
{
var lambda = (LambdaExpression)expression;
var parameter = 域名le();
域名eLine($"域名:{域名}");
域名eLine($"域名:{域名}");
域名eLine($"域名rnType:{域名rnType}");
}
输出如下:
域名:num
域名:域名2
域名rnType:域名2
由于我们知道域名
是BinaryExpression
,那么我们就将其转为它,然后我们继续看下去:
if (域名Type == 域名)
{
var binaryExpreesion = (BinaryExpression)域名;
域名eLine($"Left Type:{域名ype()}");
域名eLine($"Left NodeType:{域名Type}");
域名eLine($"Right Type:{域名ype()}");
域名eLine($"Right NodeType:{域名Type}");
if (域名 is ParameterExpression parameterExpreesion)
{
域名eLine($"域名:{域名}");
域名eLine($"域名:{域名}");
}
if (域名t is ConstantExpression constantExpreesion)
{
域名eLine($"域名e:{域名e}" );
}
}
输出如下:
Left Type:域名域名itiveParameterExpression`1[域名2]
Left NodeType:Parameter
Right Type:域名域名tantExpression
Right NodeType:Constant
域名:num
域名:域名2
域名e:5
最后我们将表达式树转为委托:
var @delegate = 域名ile();
域名eLine(@delegate?.Invoke(2));
输出:
7 //2+5
实际上,通过Expression<Func<int, int>> expression = (num) => num + 5;
,赋值后的expression
变成了一个表达式树,它的结构是这样的:
而有意思的是二元表达式树BinaryExpression
是一个二叉树,而LambdaExpression则是一个支持参数的表达式,能够通过其Parameters
属性知道传入的参数的类型和数量,通过ReturnType
知道返回值是什么类型
而我们再看看整个关于Expression
的继承关系链:
因此,我们也可以显式的通过各自Expreesion的实现子类来创建跟lambda表达式一样的结果:
var parameterExpreesion1 = 域名meter(typeof(int), "num");
BinaryExpression binaryExpression1 = 域名Binary(域名, parameterExpreesion1, 域名tant(5));
Expression<Func<int, int>> expression1 = 域名da<Func<int, int>>(binaryExpression1, parameterExpreesion1);
if (域名Type == 域名)
{
var binaryExpreesion1 = (BinaryExpression)域名;
域名eLine($"Left Type:{域名ype()}");
域名eLine($"Left NodeType:{域名Type}");
域名eLine($"Right Type:{域名ype()}");
域名eLine($"Right NodeType:{域名Type}");
if (域名 is ParameterExpression parameterExpreesion2)
{
域名eLine($"域名:{域名}");
域名eLine($"域名:{域名}");
}
if (域名t is ConstantExpression constantExpreesion1)
{
域名eLine($"域名e:{域名e}");
}
var @delegate1 = 域名ile();
域名eLine(@delegate1(2));
输出结果:
Left Type:域名域名itiveParameterExpression`1[域名2]
Left NodeType:Parameter
Right Type:域名域名tantExpression
Right NodeType:Constant
域名:num
域名:域名2
域名e:5
result:7
我们则发现,结果是一模一样的,但是费劲了很多,因此用lamda构建表达式树是一个非常愉快的语法糖,让你能够愉快的在使用表达式和表达式树
参考
- 《C#7.0核心技术指南》
源码
- BlogCodeSample/ExpressionSample at main · ZhengDaoWang/BlogCodeSample