我的编程空间,编程开发者的网络收藏夹
学习永远不晚

带你一文了解C#中的Expression

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

带你一文了解C#中的Expression

前言

我们书接上文,我们在了解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

总结

到此这篇关于C#中Expression的文章就介绍到这了,更多相关C#的Expression内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

带你一文了解C#中的Expression

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

一文带你了解C++中queue的使用

C++中的queue是一种容器,用于在FIFO(先进先出)原则下存储和管理元素。本篇文章将深入探讨C++中的queue,包括它的定义、使用、原理和示例,感兴趣的可以了解一下
2023-05-18

一文带你了解C++中deque的使用

C++中的deque是一种双端队列,可以在队列的前端和后端进行插入元素和删除操作,同时可以视作一个长度不定的数组,支持高效的插入和删除操作。本篇文章将深入探讨C++中的deque的使用,感兴趣的可以了解一下
2023-05-18

一文带你了解C#中的协变与逆变

这篇文章介绍了C#中协变和逆变的相关知识,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
2023-02-26

一文带你快速了解C/C++标准库中的ptrdiff_t

ptrdiff_t是C/C++标准库中定义的一个与机器相关的数据类型,ptrdiff_t类型变量通常用来保存两个指针减法操作的结果,下面这篇文章主要给大家介绍了关于C/C++标准库中ptrdiff_t的相关资料,需要的朋友可以参考下
2022-11-16

一文带你了解Golang中的WaitGroups

WaitGroups是同步你的goroutines的一种有效方式。这篇文章主要来和大家聊聊Golang中WaitGroups的使用,感兴趣的小伙伴可以跟随小编一起了解一下
2023-03-14

一文带你了解C++中的字符替换方法

这篇文章主要为大家详细介绍了C++中常用的几个字符替换方法,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以跟随小编一起了解一下
2023-05-18

一文带你了解Java

今天就跟大家聊聊有关一文带你了解Java,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java 简介Java是由Sun Microsystems公司(现已被oracle公司收购)于1
2023-05-31

一文带你深入了解C++中的类型转换

在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与接收返回值类型不一致时,就需要发生类型转化。本文主要介绍了C++中常见的四个类型转换,需要的可以参考一下
2022-12-27

一文带你了解C#操作MySql的方法

工作中大多数情况下用的都是MySql但一直没有记录,相关操作。这篇文章以便MySql.Data库进行MySql操作,使用C#执行SQL语句,造个轮子
2023-03-20

一文带你了解MySQL中的事务

目录一.什么是事务二.事务操作演示小结三.事务的特性四.事务的隔离级别概述四种隔离级别脏读、不可重复读、幻读操作一.什么是事务在mysql中的事务(Transaction)是由存储引擎实现的,在MySQL中,只有InnoDB存储引擎才支持
2023-02-17

一文带你深入了解C++中音频PCM数据

PCM(PulseCodeModulation)也被称为脉冲编码调制,是数字通信的编码方式之一。这篇文章主要和大家聊聊C++中音频PCM数据的相关操作,需要的可以参考一下
2023-02-10

一文带你了解Python中的枚举(enum)

这篇文章一文带你了解Python中的枚举(enum),在Python中,枚举和我们在对象中定义的类变量时一样的,每一个类变量就是一个枚举项,需要的朋友可以参考下
2023-05-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录