带你一文了解C#中的Expression
作者:RyzenAdorer 发布时间:2023-04-20 04:37:57
前言
我们书接上文,我们在了解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核心技术指南》
源码
BlogCodeSample/ExpressionSample at main · ZhengDaoWang/BlogCodeSample
来源:https://www.cnblogs.com/ryzen/p/15674630.html


猜你喜欢
- 适合人群学完Java基础想通过Java快速构建web应用程序想学习或了解SpringBoot背景本节给大家讲讲 Java的Spri
- IntelliJ IDEA一个吸引人的地方在于,他有比较好的反编译工具,这让Eclipse用户牙痒痒。但不要紧,本文介绍如何在Eclipse
- 本文实例为大家分享了一个基于JAVA的知乎爬虫,抓取知乎用户基本信息,基于HttpClient 4.5,供大家参考,具体内容如下详细内容:抓
- 本文实例讲述了Android编程之绘制文本(FontMetrics)实现方法。分享给大家供大家参考,具体如下:Canvas 作为绘制文本时,
- 本文实例为大家分享了Android投票进度条的具体代码,供大家参考,具体内容如下效果展示功能属性介绍<!-- MatchSupport
- 一.HashMap 和Hashtable 的区别我们先看2个类的定义 public class Hashtable exten
- 今天在开发的过程中,遇到java.lang.ExceptionInInitializerError异常,百度查了一下,顺便学习学习,做个笔记
- webview是一个很简单的功能,代码没有什么逻辑上的难度,只是需要注意权限上的问题。其实在安卓编程的过程当中,权限问题可以算是出现的比较多
- Java泛型映射不同的值类型详解前言:一般来说,开发人员偶尔会遇到这样的情形: 在一个特定容器中映射任意类型的值。然而Java 集合API只
- 一、Shiro简介:Apache Shiro是一个Java的安全(权限)框架。Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在J
- Android:AIDL和远程Service调用本讲的内容,理解起来很难,也许你看了很多资料也看不明白,但是用起来缺简单的要命。所以我们干脆
- 代理模式代理模式(Proxy Pattern)是一种结构性模式。代理模式为一个对象提供了一个替身,以控制对这个对象的访问。即通过代理对象访问
- 一个让人赏心悦目的界面对软件来说非常重要,因此图形图像资源也显得非常重要。本讲就要谈一谈Android中处理图形图像的最重要的一个类Draw
- Android文件存储看下网上随处可以搜到的文件存储套路if(Environment.MEDIA_MOUNTED.equals(Enviro
- springboot配置templates直接访问springboot下的templates目录的资源默认是受保护的,类似于javaweb项
- 前言今天在做新需求的时候,活动有多个类型可以选择,UI给的设计图为多行多列排版,且单项选择,细细想来,谷歌并没有为我们提供类似的控件,初步设
- 我们初学java的第一个程序是"hello world" public class HelloWorld {  
- springmvc控制登录用户session失效后跳转登录页面,废话不多少了,具体如下:第一步,配置 web.xml <session
- 一、前言 网上有许多的多线程断点续传操作,但总是写的很云里雾里,或者
- 实践过程效果代码public partial class GlorifyCheckBox : CheckBox {