C# .Net学习笔记—— Expression 表达式目录树

news2024/9/23 3:26:40

一、什么是表达式目录树

(1)Expression我们称为是表达式树,是一种数据结构体,用于存储需要计算,运算的一种结构,这种结构可以只是存储,而不进行运算。通常表达式目录树是配合Lambda一起来使用的,lambda可以是匿名方法,当然也可以使用Expression来动态的创建!

二、Func与Expression的区别

1、Func是方法

 Func<int, int, int> func = (m, n) => m * n + 2;
 Console.WriteLine(func.Invoke(1, 1)); 
//运算:1*1+2=3

 2、Expression是数据结构

//lambda表达式声明表达式目录树
Expression<Func<int, int, int>> exp = (m, n) => m * n + 2;
int result = exp.Compile().Invoke(1, 2);
Console.WriteLine(result); 
//运算:1*2+2=4

注意:Expression只能为1行(如下图会报错)

3、使用ILSpy反编译解析看一下

调一下格式更好看一点

            ParameterExpression parameterExpression = Expression.Parameter(typeof(int), "m");
            ParameterExpression parameterExpression2 = Expression.Parameter(typeof(int), "n");

            var multiply = Expression.Multiply(parameterExpression, parameterExpression2);
            var constant = Expression.Constant(2,typeof(int));
            var add = Expression.Add(multiply, constant);

            Expression<Func<int, int, int>> exp =
                Expression.Lambda<Func<int, int, int>>(
                        add,
                        new ParameterExpression[2]
                        {
                            parameterExpression, parameterExpression2
                        });
打印看看结果
      int result = exp.Compile().Invoke(11, 12);
            Console.WriteLine(result);

得到134,与m*n+2得出结果一致

4、拼装练习

(1)练习一:

(2)练习二

(3)练习三

5、动态生成硬编码(通用、性能好)

需求:我希望复制一个People出来

    public class People 
    {
        public int Age;
        public string Name;
    }
    public class PeopleCopy 
    {
        public int Age;
        public string Name;
    }

方法1:通过硬编码直接赋值

People people = new People()
{
   Age = 18,
   Name = "吴彦祖"
};
PeopleCopy peopleCopy = new PeopleCopy()
{
   Age = people.Age,
   Name = people.Name,
};

方法2:通过反射赋予

方法3:通过Json序列化与反序列化赋值

第一种方法性能最好,但是不够通用。方法2和方法3性能不好。

方法4:

这时候可以考虑使用表达式目录树来动态生成硬编码

思路:用表达目录树动态生成硬编码,生成保存到字典里,下次再调用的时候则直接从字典里拿。

 public class ExpressionMapper
    {
        private static Dictionary<string, object> _dic = new Dictionary<string, object>();

        public static TOut Trans<TIn, TOut>(TIn tIn) 
        {
            string key = string.Format("funckey_{0}_{1}", typeof(TIn).FullName, typeof(TOut).FullName);
            if (!_dic.ContainsKey(key))
            {
                ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
                List<MemberBinding> memberBindingList = new List<MemberBinding>();

                foreach (var item in typeof(TOut).GetProperties())
                {
                    MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }

                foreach (var item in typeof(TOut).GetFields())
                {
                    MemberExpression field = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                    MemberBinding memberBinding = Expression.Bind(item, field);
                    memberBindingList.Add(memberBinding);
                }
                MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
                Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
                {
                    parameterExpression
                });
                _dic[key] = lambda.Compile();
            }
            return ((Func<TIn, TOut>)_dic[key]).Invoke(tIn);
        }

方法5:泛型缓存(相比方法4可以节省读取字典时候的消耗)

 public class ExpressionGenericMapper<TIn, TOut>
    {
        private static Func<TIn, TOut> _Func;
        static ExpressionGenericMapper()
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            List<MemberBinding> memberBindingList = new List<MemberBinding>();

            foreach (var item in typeof(TOut).GetProperties())
            {
                MemberExpression property = Expression.Property(parameterExpression, typeof(TIn).GetProperty(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, property);
                memberBindingList.Add(memberBinding);
            }

            foreach (var item in typeof(TOut).GetFields())
            {
                MemberExpression field = Expression.Field(parameterExpression, typeof(TIn).GetField(item.Name));
                MemberBinding memberBinding = Expression.Bind(item, field);
                memberBindingList.Add(memberBinding);
            }
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
            {
                parameterExpression
            });
            _Func = lambda.Compile();
        }

        public static TOut Trans(TIn t) 
        {
            return _Func(t);
        }

看一下字典缓存和泛型类缓存消耗的时间,明显可以看到通过泛型类缓存的性能更好,因为节省了查找字典的性能消耗。

         PrintExecutionTime(() =>
            {
                Console.WriteLine("通过字典缓存,第一次消耗时间:");
                PeopleCopy copy = ExpressionMapper.Trans<People, PeopleCopy>(new People() { Age = 10, Name = "哇哈哈" });
            });
            PrintExecutionTime(() =>
            {
                Console.WriteLine("通过字典缓存,第二次消耗时间:");
                PeopleCopy copy2 = ExpressionMapper.Trans<People, PeopleCopy>(new People() { Age = 10, Name = "哇哈哈" });
            });


            PrintExecutionTime(() =>
            {
                Console.WriteLine("通过泛型类缓存,第一次消耗时间:");
                PeopleCopy copy3 = ExpressionGenericMapper<People, PeopleCopy>.Trans(new People() { Age = 11, Name = "啦啦啦" });
            });
            PrintExecutionTime(() =>
            {
                Console.WriteLine("通过泛型类缓存,第二次消耗时间:");
                PeopleCopy copy4 = ExpressionGenericMapper<People, PeopleCopy>.Trans(new People() { Age = 11, Name = "啦啦啦" });
            });

5、表达式目录树动态生成的用途:

可以用来替代反射,因为反射可以通用,但是性能不够

可以生成硬编码,可以提升性能

6、递归解析表达式目录树

(1)ExpressionVisitor:肯定得递归解析表达式目录树,因为不知道深度的一棵树

(2)只有一个入口叫Visit

(3)首先检查是个什么类型的表达式,然后调用对应的protected virtual

(4)得到结果继续去检查类型——调用对应的Visit方法——再检测——再调用。。。

案例:解析(m*n+2)

第一步(把m*n+2传入,入口时Visit)

第二步:检测到二元表达式,m*n+2进入VisitBinary方法.

node.Left为m*n(这里会再次调用VisitBinary方法)    node.Right为2

  第三步:m*n也时二元表达式,因此重新进入VisitBinary方法

node.Left为m(进入VisitParameter方法)  node.Right为n(进入VisitParameter方法)

第四步:m*n解析完开始解析2,会进入VisitConstant方法

基础应用:我们可以把表达式的所有+号变成-号

从下图可以发现,表达式expression变成了m*n-2

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1325085.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

关于“Python”的核心知识点整理大全32

目录 12.6.4 调整飞船的速度 settings.py ship.py alien_invasion.py 12.6.5 限制飞船的活动范围 ship.py 12.6.6 重构 check_events() game_functions.py 12.7 简单回顾 12.7.1 alien_invasion.py 12.7.2 settings.py 12.7.3 game_functions.py 12.7.4 ship.py …

Hive入门+部署

看黑马视频做的笔记 目录 概念 1.基本概述 2.基础架构 总架构 部署 1.安装MySQL 2.配置Hadoop 3.下载解压Hive 4.下载MySQL Driver包 注意&#xff01; 5.配置Hive 6.初始化元数据库 7.启动Hive&#xff08;使用Hadoop用户&#xff09; 实例 查看HDFS上表中存…

网络基础【网线的制作、OSI七层模型、集线器、交换机介绍、路由器的配置】

目录 一.网线的制作 1.1.网线的标准 1.2.水晶头的做法 二.OSI七层模型、集线器、交换机介绍 集线器&#xff08;Hub&#xff09;&#xff1a; 交换机&#xff08;Switch&#xff09;&#xff1a; 三.路由器的配置 3.1.使用 3.2.常用的功能介绍 1、如何管理路由器 2、家…

CW32单片机在智能马桶的应用介绍

智能科技的迅速发展使得我们的日常生活变得更加便捷和舒适。智能马桶作为其中一种智能家居产品&#xff0c;通过单片机接受和处理来自传感器的数据&#xff0c;然后通过控制模块对智能马桶的各项功能进行控制&#xff0c;实现对智能马桶的全面控制和调节。本文将介绍CW32单片机…

苹果发布iOS 17.2.1版本更新

12月20日&#xff0c;苹果向iPhone用户推送了iOS 17.2.1更新。苹果公司在更新日志中称&#xff1a;“本更新包含了重要的错误修复&#xff0c;并解决了某些情况下电池电量较预期更快耗尽的问题。” 据报道&#xff0c;iOS 17系统在发布初期便出现了一系列问题&#xff0c;如发…

PSP - 结构生物学中的机器学习 (NIPS MLSB Workshop 2023.12)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/135120094 Machine Learning in Structural Biology (机器学习在结构生物学中) 网址&#xff1a;https://www.mlsb.io/ Workshop at the 37th Co…

神经科学与计算神经科学的蓬勃发展与未来趋势

导言 神经科学和计算神经科学是当前科学研究领域中备受关注的方向。本文将深入研究这两个领域的发展历程、遇到的问题、解决过程&#xff0c;以及未来的可用范围。我们还将关注在各国的应用现状以及未来的研究趋势&#xff0c;探讨如何在竞争中取胜&#xff0c;以及在哪些方面发…

大数据处理与分析

掌握分布式并行编程框架MapReduce掌握基于内存的分布式计算框架Spark理解MapReduce的工作流程、Spark运行原理熟悉机器学习概念 一.MapReduce Hadoop MapReduce是一个软件框架&#xff0c;基于该框架能够容易地编写应用程序&#xff0c;这些应用程序能够运行在由上千个商用机器…

机器学习数据的清洗,转化,汇总及建模完整步骤(基于Titanic数据集)

目录 介绍&#xff1a; 一、数据 二、检查数据缺失 三、数据分析 四、数据清洗 五、数据类别转化 六、数据汇总和整理 七、建模 介绍&#xff1a; 线性回归是一种常用的机器学习方法&#xff0c;用于建立一个输入变量与输出变量之间线性关系的预测模型。线性回归的目标…

vs code创建工程,以koa框架为例

以下内容为本人的学习笔记&#xff0c;如需要转载&#xff0c;请声明原文链接 微信公众号「englyf」https://mp.weixin.qq.com/s/x2OXMTaLlxb_Os7NDHrKsg 这里以应用 koa 框架写一个 http 服务器为例&#xff0c;来说明怎么用 vs code 创建工程。 进入 vs code 后&#xff0c…

云服务器 nginx自启动、mysql自启动、pyhton后端自启动

nginx自启动 方法一&#xff1a; 1、建立启动文件 vim /usr/lib/systemd/system/nginx.service [Unit] Descriptionnginx - high performance web server Afternetwork.target remote-fs.target nss-lookup.target[Service] Typeforking ExecStart/usr/local/nginx/sbin/ng…

DMA实验3-外设到内存搬运

实验要求 使用 DMA 的方式将串口接收缓存寄存器的值搬运到内存中&#xff0c;同时闪烁 LED1 。 CubeMX 配置 DMA 配置&#xff1a; 串口中断配置 代码实现 如何判断串口接收是否完成&#xff1f;如何知道串口收到数据的长度&#xff1f; 使用串口空闲中断&#xff08;IDL…

2023优秀开源项目获选榜名单(开放原子开源基金会)|JeecgBoot 成功入选

JeecgBoot 是一个开源的企业级低代码开发平台&#xff0c;它成功入选2023年度生态开源项目&#xff0c;这是对其十年坚持开源的认可。作为一个开源项目&#xff0c;JeecgBoot 在过去的十年里一直秉承着开放、共享、协作的理念&#xff0c;不断推动着开源社区的发展。 2023年开放…

华为配置IPv4静态路由与静态BFD联动示例

组网需求 如图1所示&#xff0c;SwitchA通过SwitchB和NMS跨网段相连。在SwitchA上通过静态路由与NMS进行正常通信。在SwitchA和SwitchB之间实现毫秒级故障感知&#xff0c;提高收敛速度 配置思路 采用如下思路配置IPv4静态路由与静态BFD联动&#xff1a; 在SwitchA和SwitchB上…

LVS+keepalived小白都看得懂也不来看?

1 高可用集群 1.1 一个合格的集群应该具备的特性 1.负载均衡 LVS Nginx HAProxy F5 2.健康检查&#xff08;使得调度器检查节点状态是否可以正常运行&#xff0c;调度器&#xff08;负载均衡器&#xff09;也要做健康检查&#xff09;for调度器/节点服务器 keeplived hearb…

aws配置以及下载 spaceNet6 数据集

一&#xff1a;注册亚马逊账号 注册的时候&#xff0c;唯一需要注意的是信用卡绑定&#xff0c;这个可以去淘宝买&#xff0c;搜索aws匿名卡。 注册完记得点击登录&#xff0c;记录一下自己的账户ID哦&#xff01; 二&#xff1a;登录自己的aws账号 2.1 首先创建一个用户 首…

2023 英特尔On技术创新大会直播 |AI小模型更有性价比

前言&#xff1a; 今年是引爆AI的一年&#xff0c;从幼儿园的小朋友到80岁的老奶奶都认识AI&#xff0c;享受AI带来的便捷&#xff0c;都在向市场要智能&#xff0c;但AI的快速发展离不开底层硬件设施的革新。 英特尔是全球知名的半导体公司&#xff0c;专注于计算机处理器和芯…

FPGA模块——以太网芯片MDIO读写

FPGA模块——以太网MDIO读写 MDIO接口介绍MDIO接口代码&#xff08;1&#xff09;MDIO接口驱动代码&#xff08;2&#xff09;使用MDIO驱动的代码 MDIO接口介绍 MDIO是串行管理接口。MAC 和 PHY 芯片有一个配置接口&#xff0c;即 MDIO 接口&#xff0c;可以配置 PHY 芯片的工…

【实时绘画】krita + comfyUI 实时绘画 儿童海报

1&#xff1a;打开comfyUI 2: 打开krita 打开 cd custom_nodes 输入命令 安装控件 git clone https://github.com/Acly/comfyui-tooling-nodes.git

人工智能与底层架构:构建智能引擎的技术支柱

导言 人工智能与底层架构的交融塑造了智能系统的基石&#xff0c;是推动智能时代发展的关键动力&#xff0c;本文将深入研究人工智能在底层架构中的关键作用&#xff0c;以及它对智能引擎的技术支持&#xff0c;探讨人工智能在计算机底层架构中的作用&#xff0c;以及这一融合如…