我们书接上文,我们在了解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;
Console.WriteLine($"NodeType:{expression.NodeType}");
Console.WriteLine($"Body:{expression.Body}");
Console.WriteLine($"Body Type: {expression.Body.GetType()}");
Console.WriteLine($"Body NodeType: {expression.Body.NodeType}");

输出如下:

NodeType:Lambda
Body:(num + 5)
Body Type: System.Linq.Expressions.SimpleBinaryExpression
Body NodeType: Add

我们将expression转为LambdaExpression看看都有啥:

if (expression.NodeType == ExpressionType.Lambda)
{
var lambda = (LambdaExpression)expression;
var parameter = lambda.Parameters.Single();
Console.WriteLine($"parameter.Name:{parameter.Name}");
Console.WriteLine($"parameter.Type:{parameter.Type}");
Console.WriteLine($"parameter.ReturnType:{lambda.ReturnType}");
}

输出如下:

parameter.Name:num
parameter.Type:System.Int32
parameter.ReturnType:System.Int32

由于我们知道expression.Body是BinaryExpression,那么我们就将其转为它,然后我们继续看下去:

if (expression.Body.NodeType == ExpressionType.Add)
{
var binaryExpreesion = (BinaryExpression)expression.Body; Console.WriteLine($"Left Type:{binaryExpreesion.Left.GetType()}");
Console.WriteLine($"Left NodeType:{binaryExpreesion.Left.NodeType}"); Console.WriteLine($"Right Type:{binaryExpreesion.Right.GetType()}");
Console.WriteLine($"Right NodeType:{binaryExpreesion.Right.NodeType}"); if (binaryExpreesion.Left is ParameterExpression parameterExpreesion)
{
Console.WriteLine($"parameterExpreesion.Name:{parameterExpreesion.Name}");
Console.WriteLine($"parameterExpreesion.Type:{parameterExpreesion.Type}");
} if (binaryExpreesion.Right is ConstantExpression constantExpreesion)
{
Console.WriteLine($"constantExpreesion.Value:{constantExpreesion.Value}" );
}
}

输出如下:

Left Type:System.Linq.Expressions.PrimitiveParameterExpression`1[System.Int32]
Left NodeType:Parameter
Right Type:System.Linq.Expressions.ConstantExpression
Right NodeType:Constant
parameterExpreesion.Name:num
parameterExpreesion.Type:System.Int32
constantExpreesion.Value:5

最后我们将表达式树转为委托:

var @delegate = expression.Compile();
Console.WriteLine(@delegate?.Invoke(2));

输出:

7 //2+5

实际上,通过Expression<Func<int, int>> expression = (num) => num + 5;,赋值后的expression 变成了一个表达式树,它的结构是这样的:

而有意思的是二元表达式树BinaryExpression是一个二叉树,而LambdaExpression则是一个支持参数的表达式,能够通过其Parameters属性知道传入的参数的类型和数量,通过ReturnType知道返回值是什么类型

而我们再看看整个关于Expression的继承关系链:

因此,我们也可以显式的通过各自Expreesion的实现子类来创建跟lambda表达式一样的结果:

var parameterExpreesion1 = Expression.Parameter(typeof(int), "num");
BinaryExpression binaryExpression1 = Expression.MakeBinary(ExpressionType.Add, parameterExpreesion1, Expression.Constant(5));
Expression<Func<int, int>> expression1 = Expression.Lambda<Func<int, int>>(binaryExpression1, parameterExpreesion1); if (expression1.Body.NodeType == ExpressionType.Add)
{
var binaryExpreesion1 = (BinaryExpression)expression1.Body; Console.WriteLine($"Left Type:{binaryExpreesion1.Left.GetType()}");
Console.WriteLine($"Left NodeType:{binaryExpreesion1.Left.NodeType}"); Console.WriteLine($"Right Type:{binaryExpreesion1.Right.GetType()}");
Console.WriteLine($"Right NodeType:{binaryExpreesion1.Right.NodeType}"); if (binaryExpreesion1.Left is ParameterExpression parameterExpreesion2)
{
Console.WriteLine($"parameterExpreesion.Name:{parameterExpreesion2.Name}");
Console.WriteLine($"parameterExpreesion.Type:{parameterExpreesion2.Type}");
} if (binaryExpreesion1.Right is ConstantExpression constantExpreesion1)
{
Console.WriteLine($"constantExpreesion.Value:{constantExpreesion1.Value}");
} var @delegate1 = expression1.Compile();
Console.WriteLine(@delegate1(2));

输出结果:

Left Type:System.Linq.Expressions.PrimitiveParameterExpression`1[System.Int32]
Left NodeType:Parameter
Right Type:System.Linq.Expressions.ConstantExpression
Right NodeType:Constant
parameterExpreesion.Name:num
parameterExpreesion.Type:System.Int32
constantExpreesion.Value:5
result:7

我们则发现,结果是一模一样的,但是费劲了很多,因此用lamda构建表达式树是一个非常愉快的语法糖,让你能够愉快的在使用表达式和表达式树

参考

  • 《C#7.0核心技术指南》

源码

了解C#的Expression的更多相关文章

  1. AutoMapper:Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type

    异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 应用场景:ViewModel==>Mode映射的时候出错 AutoMappe ...

  2. OpenCASCADE Expression Interpreter by Flex & Bison

    OpenCASCADE Expression Interpreter by Flex & Bison eryar@163.com Abstract. OpenCASCADE provide d ...

  3. Expression Blend创建自定义按钮

    在 Expression Blend 中,我们可以在美工板上绘制形状.路径和控件,然后修改其外观和行为,从而直观地设计应用程序.Button按钮也是Expression Blend最常用的控件之一,在 ...

  4. [C#] C# 知识回顾 - 表达式树 Expression Trees

    C# 知识回顾 - 表达式树 Expression Trees 目录 简介 Lambda 表达式创建表达式树 API 创建表达式树 解析表达式树 表达式树的永久性 编译表达式树 执行表达式树 修改表达 ...

  5. Could not evaluate expression

    VS15 调试变量不能显示值,提示:Could not evaluate expression 解决办法: 选择"在调试时显示运行以单击编辑器中的按钮"重启VS即可. 可参考:Vi ...

  6. 使用Expression实现数据的任意字段过滤(1)

    在项目常常要和数据表格打交道. 现在BS的通常做法都是前端用一个js的Grid控件, 然后通过ajax的方式从后台加载数据, 然后将数据和Grid绑定. 数据往往不是一页可以显示完的, 所以要加分页: ...

  7. 使用Expression实现数据的任意字段过滤(2)

    上一篇<使用Expression实现数据的任意字段过滤(1)>, 我们实现了通过CriteriaCollectionHandler对象来处理集合数据过滤.通过适当的扩展, 应该可以满足一般 ...

  8. React Native JSX value should be expression or a quoted JSX text.

    问题描述:  我在使用props时候, 我的写法是这样的 ... <View> <Person name='john' age=32 gender=true></Pers ...

  9. [LeetCode] Ternary Expression Parser 三元表达式解析器

    Given a string representing arbitrarily nested ternary expressions, calculate the result of the expr ...

  10. [LeetCode] Regular Expression Matching 正则表达式匹配

    Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...

随机推荐

  1. [源码解析] PyTorch分布式(5) ------ DistributedDataParallel 总述&如何使用

    [源码解析] PyTorch 分布式(5) ------ DistributedDataParallel 总述&如何使用 目录 [源码解析] PyTorch 分布式(5) ------ Dis ...

  2. 菜鸡的Java笔记 开发支持类库

    开发支持类库 SupportClassLibrary        观察者设计模式的支持类库                    content (内容)        什么是观察者设计模式呢?   ...

  3. 菜鸡的Java笔记 java基础类库 BaseClassLibrary

    java基础类库 BaseClassLibrary        StringBuffer 类的特点        StringBuffer,StringBuilder,String 类之间的关系   ...

  4. InnoDB 索引详解

    1.什么是索引 索引是存储引擎用于快速找到记录的一种数据结构. 2.索引有哪些数据结构 顺序查找结构:这种查找效率很低,复杂度为O(n).大数据量的时候查询效率很低. 有序的数据排列:二分查找法又称折 ...

  5. [atAGC050A]AtCoder Jumper

    考虑二叉树的结构,但并不容易构造从叶子返回的边 (以下为了方便,将所有点编号为$[0,n)$) 对于$i$,选择$2i\ mod\ n$和$(2i+1)\ mod\ n$这两条出边 从二叉树的角度并不 ...

  6. [atARC094D]Worst Case

    首先,容易证明满足条件的$ip_{i}$必然是一个前缀 将其看成一张二分图,$i$向满足$ip_{i}<xy$的$p_{i}$连边,即找到一个前缀满足其有完美匹配 二分枚举前缀长度$k$,根据h ...

  7. 【Microsoft Azure 的1024种玩法】六、使用Azure Cloud Shell对Linux VirtualMachines 进行生命周期管理

    [文章简介] Azure Cloud Shell 是一个用于管理 Azure 资源的.可通过浏览器访问的交互式经验证 shell. 它使用户能够灵活选择最适合自己工作方式的 shell 体验,本篇文章 ...

  8. CF611F New Year and Cleaning

    题意 CF611F New Year and Cleaning 想法 这个题是\(NOIP2020\)的弱化版.. 我们把所有在二维上的点都一起考虑,那么所有点对于一个步骤的移动是相当于这些所有点所组 ...

  9. AtCoder Beginner Contest 204

    身败名裂了,\(AK\)场转掉分场. 都是水题不说了. 这篇文鸽了.

  10. 卷积神经网络(Convolutional Neural Networks)CNN

     申明:本文非笔者原创,原文转载自:http://www.36dsj.com/archives/24006 自今年七月份以来,一直在实验室负责卷积神经网络(Convolutional Neural ...