当前位置: 首页 > article >正文

在C#中动态访问对象属性时,用表达式树可以获得高效性能

在C#中如何用表达式树动态访问对象属性的问题。用户可能已经知道反射的基本用法,但想用表达式树来提高性能,因为表达式树编译后的委托执行速度比反射快。
首先,表达式树的基本概念。表达式树允许在运行时构建代码,并编译成可执行的委托,这样避免了反射带来的性能开销。用户需要一个例子,所以我要构造一个简单的类,比如Person,然后动态获取它的属性,比如Name。
接下来,需要考虑如何构建表达式树。访问属性通常涉及参数表达式、属性访问表达式,以及可能的转换(如果属性是值类型需要装箱)。步骤大致是:创建参数表达式,生成属性访问表达式,然后转换成Lambda表达式,最后编译成委托。
然后,需要处理泛型方法,因为用户可能希望这个方法适用于任何对象和属性类型。所以方法应该是泛型的,比如GetPropertyAccessor<T, TProp>,这样类型安全,同时减少装箱拆箱。
还要考虑错误处理,比如属性是否存在,但用户可能暂时不需要,例子中可以忽略,但实际使用时可能需要添加。
然后,编写示例代码,包括Person类,创建表达式树,编译成委托,并演示如何使用。用户可能还需要比较性能,所以可以提到与反射的性能对比,但例子中可以不实现。
最后,检查代码是否正确,比如Expression.Property的正确使用,Lambda表达式的参数是否正确,以及编译后的委托是否正确调用。
可能遇到的坑:值类型属性需要转换为object,所以可能需要Expression.Convert。例如,如果属性是int类型,直接返回object需要转换,否则会出错。但如果是泛型方法返回TProp,可能不需要,但如果是返回object,则需要处理。
在用户例子中,返回的是object,所以可能需要Convert表达式。但用户提供的示例代码可能没有处理,需要检查是否正确。比如,如果TProp是值类型,访问时需要转换为object,否则委托返回的是值类型,导致装箱问题。因此,应该在表达式树中添加Convert。
不过,在用户提供的示例代码中,GetPropertyAccessor返回Func<object, object>,所以当TProp是值类型时,Expression.Property会返回值类型,需要转换为object。因此,在表达式树中应该用Expression.Convert将属性表达式转换为object类型。
例如:
Expression.Property(param, propertyInfo) 是TProp类型,如果TProp是值类型,直接赋值给object会装箱,所以需要:
Expression.Convert(Expression.Property(param, propertyInfo), typeof(object))
这样,生成的lambda表达式就是Expression<Func<object, object>>,正确处理值类型和引用类型。
但用户提供的示例代码中可能没有这一步,需要检查。比如,原代码中的表达式是:
Expression.Lambda<Func<object, object>>(propertyAccess, param);
而propertyAccess是Expression.Property(param, propertyInfo),此时如果propertyInfo是值类型,则propertyAccess的类型是值类型,无法直接转换为object,所以需要Convert。
因此,正确的代码应该在获取属性后,添加一个Convert表达式。所以,修改后的表达式应该是:
var propertyAccess = Expression.Property(param, propertyInfo);
if (propertyAccess.Type.IsValueType)
{
propertyAccess = Expression.Convert(propertyAccess, typeof(object));
}
或者更简单的方式,不管是否是值类型,都转换为object:
propertyAccess = Expression.Convert(propertyAccess, typeof(object));
但这样可能对于引用类型会多一次转换,不过不影响结果。因此,在构建表达式树时,应该添加Convert。
所以,用户提供的示例代码可能需要调整,添加Convert步骤,否则当属性是值类型时会出错。
总结,正确的表达式树构建步骤应该是:

  1. 创建参数表达式:ParameterExpression param = Expression.Parameter(typeof(object), "x");
  2. 转换参数为具体类型:UnaryExpression convertedParam = Expression.Convert(param, typeof(T));
  3. 访问属性:MemberExpression propertyAccess = Expression.Property(convertedParam, propertyInfo);
  4. 将属性值转换为object(如果需要):UnaryExpression convertedProperty = Expression.Convert(propertyAccess, typeof(object));
  5. 构建Lambda表达式:var lambda = Expression.Lambda<Func<object, object>>(convertedProperty, param);
    但用户希望的是通用的方法,所以可能需要泛型方法,或者正确处理类型转换。
    可能用户提供的例子中没有处理这一点,导致值类型属性无法正确返回。因此,在编写示例时,需要注意添加Convert。
    现在,我需要将这些思考整理成一个清晰的示例,确保代码正确,并解释每一步的作用,同时指出可能的注意事项,比如性能优势和类型转换的问题。
using System;
using System.Linq.Expressions;
using System.Reflection;public class Person
{public string Name { get; set; }
}public static class PropertyAccessor
{// 创建泛型委托缓存(提升性能)private static readonly Dictionary<string, Delegate> _accessorCache = new Dictionary<string, Delegate>();public static Func<object, object> GetPropertyAccessor(Type objectType, string propertyName){var key = $"{objectType.FullName}.{propertyName}";if (!_accessorCache.TryGetValue(key, out var accessor)){// 获取属性信息var propertyInfo = objectType.GetProperty(propertyName);if (propertyInfo == null) throw new ArgumentException("Property not found");// 构建表达式树var param = Expression.Parameter(typeof(object), "obj");var convertedParam = Expression.Convert(param, objectType); // 转换输入对象为具体类型var propertyAccess = Expression.Property(convertedParam, propertyInfo);var convertResult = Expression.Convert(propertyAccess, typeof(object)); // 处理值类型装箱var lambda = Expression.Lambda<Func<object, object>>(convertResult, param);accessor = lambda.Compile();_accessorCache[key] = accessor;}return (Func<object, object>)accessor;}
}// 使用示例
var person = new Person { Name = "Alice" };
var accessor = PropertyAccessor.GetPropertyAccessor(typeof(Person), "Name");
var name = accessor(person); // 返回 "Alice"

注意事项

  1. 线程安全:缓存使用需考虑线程同步
  2. 内存管理:长期运行的应用程序需注意缓存大小
  3. 类型兼容:确保输入对象可转换为目标类型

如果需要支持更复杂的场景(如嵌套属性访问、索引器等),可以通过组合多个表达式节点来实现更复杂的访问逻辑。

相关文章:

在C#中动态访问对象属性时,用表达式树可以获得高效性能

在C#中如何用表达式树动态访问对象属性的问题。用户可能已经知道反射的基本用法&#xff0c;但想用表达式树来提高性能&#xff0c;因为表达式树编译后的委托执行速度比反射快。 首先&#xff0c;表达式树的基本概念。表达式树允许在运行时构建代码&#xff0c;并编译成可执行的…...

Nginx实战_高性能Web服务器与反向代理的配置全解

1. 引言 1.1 Nginx简介 Nginx(发音为 “engine-x”)是一款轻量级、高性能的HTTP服务器和反向代理服务器。它以其高并发处理能力和低资源消耗而闻名,广泛应用于互联网企业中。Nginx不仅可以作为静态文件服务器,还可以通过反向代理功能与后端应用服务器协同工作。 1.2 Ngi…...

使用html css js 来实现一个服装行业的企业站源码-静态网站模板

最近在练习 前端基础&#xff0c;html css 和js 为了加强 代码的 熟悉程序&#xff0c;就使用 前端 写了一个个服装行业的企业站。把使用的技术 和 页面效果分享给大家。 应用场景 该制衣服装工厂官网前端静态网站模板主要用于前端练习和编程练习&#xff0c;适合初学者进行 HT…...

Flutter 网络请求与数据处理:从基础到单例封装

Flutter 网络请求与数据处理&#xff1a;从基础到单例封装 在 Flutter 开发中&#xff0c;网络请求是一个非常常见的需求&#xff0c;比如获取 API 数据、上传文件、处理分页加载等。为了高效地处理网络请求和数据管理&#xff0c;我们需要选择合适的工具并进行合理的封装。 …...

数控机床设备分布式健康监测与智能维护系统MTAgent

数控机床设备分布式健康监测与智能维护系统MTAgent-v1.1融合了目前各种先进的信号处理以及信息分析算法以算法工具箱的方式&#xff0c;采用了一种开发的、模块化的结构实现信号各种分析处理&#xff0c;采用Python编程语言&#xff0c;满足不同平台需求(包括Windows、Linux)。…...

Java+SpringBoot+数据可视化的家庭记账小程序(程序+论文+安装+调试+售后等)

感兴趣的可以先收藏起来&#xff0c;还有大家在毕设选题&#xff0c;项目以及论文编写等相关问题都可以给我留言咨询&#xff0c;我会一一回复&#xff0c;希望帮助更多的人。 系统介绍 在当下这个科技日新月异、经济蓬勃向上的时代&#xff0c;中国经济正以令人瞩目的速度迅…...

基于 Ollama 工具的 LLM 大语言模型如何部署,以 DeepSeek 14B 本地部署为例

简简单单 Online zuozuo :本心、输入输出、结果 文章目录 基于 Ollama 工具的 LLM 大语言模型如何部署,以 DeepSeek 14B 本地部署为例前言下载 Ollama实际部署所需的硬件要求设置 LLM 使用 GPU ,发挥 100% GPU 性能Ollama 大模型管理命令大模型的实际运行资源消耗基于 Ollam…...

前端JS接口加密攻防实操

前端JS接口加密攻防实操 背景 在爬虫过程中&#xff0c;对数据接口各类加密的经历总结&#xff0c;无头消耗资源效率不高&#xff0c;采用浏览器兜底解密协程并行 青铜版(混淆对称加密|签名nonce等&#xff09; 解&#xff1a;根据API 调用栈&#xff0c;断点找到request参…...

Python基础--计算机基础

1. 计算机基础 1.1 硬件组成 核心硬件&#xff1a; CPU&#xff1a;负责逻辑运算与指令执行&#xff08;如Intel Core、AMD Ryzen&#xff09;内存&#xff08;RAM&#xff09;&#xff1a;临时存储运行中的程序与数据&#xff08;如DDR4 16GB&#xff09;硬盘&#xff08;HDD…...

计算机考研之数据结构:深入解析最大公约数与欧几里得算法

一、生活中的公约数应用 在日常生活中&#xff0c;经常需要处理"均分分配"问题。例如&#xff1a;要将24块巧克力和18块饼干平均分给小朋友&#xff0c;最多能分给几个小朋友&#xff1f;这就是典型的求最大公约数问题。 二、基本概念详解 约数与公约数 约数&…...

百度搜索融合 DeepSeek 满血版,开启智能搜索新篇

百度搜索融合 DeepSeek 满血版&#xff0c;开启智能搜索新篇 &#x1f680; &#x1f539; 一、百度搜索全量接入 DeepSeek &#x1f539; 百度搜索迎来重要升级&#xff0c;DeepSeek 满血版全面上线&#xff01;&#x1f389; 用户在百度 APP 搜索后&#xff0c;点击「AI」即…...

游戏引擎学习第103天

仓库:https://gitee.com/mrxiao_com/2d_game_2 回顾bug 接下来回顾一下这个bug的具体情况。当前是一个调试视图&#xff0c;我们并不是直接在调试视图下工作&#xff0c;而是在进行相关的调试。展示了地图&#xff0c;这里是环境贴图&#xff0c;上面是正在使用的环境贴图&am…...

WPF快速创建DeepSeek本地自己的客户端-基础思路版本

开发工具&#xff1a;VS 2015 开发环境&#xff1a;.Net 4.0 使用技术&#xff1a;WPF 本篇文章内容&#xff1a; 本地部署DeepSeek以后一般使用网页工具&#xff08;如Chatbox&#xff09;或者DOS窗口与其对话。本篇文章使用WPF创建一个基础版的对话工具。 一、搭建本地DeepS…...

Springboot使用Redis发布订阅自动更新缓存数据源

背景 当项目有很多数据源的时候&#xff0c;通常会在启动的时候就把数据源连接加载缓存上&#xff0c;当数据源进行变更后如何自动实时将缓存的数据源进行更新呢&#xff1f;如果是单个项目直接调接口方法就行了&#xff0c;但是涉及到分布式多个系统呢&#xff1f; 解决方案…...

spring cloud gateway限流常见算法

目录 一、网关限流 1、限流的作用 1. 保护后端服务 2. 保证服务质量 (QoS) 3. 避免滥用和恶意攻击 4. 减少资源浪费 5. 提高系统可扩展性和稳定性 6. 控制不同用户的访问频率 7. 提升用户体验 8. 避免API滥用和负载过高 9. 监控与分析 10. 避免系统崩溃 2、网关限…...

网络安全的态势如何以及如何解决?

大家好,我是AI拉呱,一个专注于人工智领域与网络安全方面的博主,现任资深算法研究员一职,兼职硕士研究生导师;热爱机器学习和深度学习算法应用,深耕大语言模型微调、量化、私域部署。曾获多次获得AI竞赛大奖,拥有多项发明专利和学术论文。对于AI算法有自己独特见解和经验…...

vue3和vue2的组件开发有什么区别

Vue3和Vue2在组件开发上存在不少差异&#xff0c;下面从多个方面详细介绍&#xff1a; 响应式原理 Vue2&#xff1a;用Object.defineProperty()方法来实现响应式。打个比方&#xff0c;它就像给对象的每个属性都安排了一个“小管家”&#xff0c;属性被访问或修改时&#xff0…...

Pytorch实现之粒子群优化算法在GAN中的应用

简介 简介:主要是采用了粒子群优化(PSO)算法来优化GAN的一个训练。PSO是一种是一种基于种群的随机优化技术。这种优化技术是通过粒子群进行的,粒子群在每次迭代中都会更新自己。对于给定的目标函数,这种方法利用一个搜索空间,在那里粒子群移动,找到所需的全局最小值。这…...

2026考研趋势深度解析:政策变化+高效工具指南

2026考研深度解析&#xff1a;趋势洞察高效工具指南&#xff0c;助你科学备战上岸 从政策变化到工具实战&#xff0c;这份千字攻略解决99%考生的核心焦虑 【热点引入&#xff1a;考研赛道进入“高难度模式”】 2025年全国硕士研究生报名人数突破520万&#xff0c;报录比预计扩…...

AI工具篇:利用DeepSeek+Kimi 辅助生成综述汇报PPT

随着科研和学术报告需求的增加&#xff0c;如何高效地准备一份结构清晰、内容充实的PPT已成为许多研究者的挑战。 传统的PPT制作过程繁琐&#xff0c;需要大量文献收集、数据分析和设计工作&#xff0c;而AI工具能够帮助提升效率&#xff0c;减少重复劳动。 本文将介绍如何使用…...

【Linux系统】—— 调试器 gdb/cgdb的使用

【Linux系统】—— 调试器 gdb/cgdb的使用 1 前置准备2 快速认识 gdb3 cgdb/gdb 的使用3.1 简单认识 cgdb3.2 打断点 / 删断点3.3 逐过程 / 逐语句3.4 查看变量3.5 快速跳转 4 cgdb/gdb 调试技巧4.1 watch4.2 「set var」确定问题原因4.3 条件断点 5 概念理解6 gdb/cgdb 指令一…...

Vue 3 中,Pinia 和 Vuex 的主要区别

总结对比表 对比项VuexPiniaAPI 设计区分 mutations/actions仅 state/actions/getters模块化嵌套式配置独立 Store&#xff0c;按需组合TypeScript需手动声明类型原生自动推断代码简洁性冗余&#xff08;需 commit/dispatch&#xff09;直接调用方法推荐场景Vue 2 升级项目/严…...

Wireshark 输出 数据包列表本身的值

在 Wireshark 中&#xff0c;如果你想输出数据包列表本身的值&#xff08;例如&#xff0c;将数据包的摘要信息、时间戳、源地址、目的地址等导出为文本格式&#xff09;&#xff0c;可以使用 导出为纯文本文件 的功能。以下是详细步骤&#xff1a; 步骤 1&#xff1a;打开 Wir…...

docker部署单机版doris,完整无坑

文章目录 一、部署1、修改内核参数2、下载Docker 开发环境镜像3、下载安装包4、启动镜像5、配置fe6、配置be7、远程连接 二、运维命令参考资料 一、部署 1、修改内核参数 在启动doris的be时&#xff0c;需要将 Linux 操作系统的内核参数设置为2000000&#xff0c;这里是Doris…...

SQL注入(SQL Injection)详解与实战

文章目录 一、什么是SQL注入&#xff1f;二、常见SQL注入类型三、手动注入步骤&#xff08;以CTF题目为例&#xff09;四、CTF实战技巧五、自动化工具&#xff1a;SQLMap六、防御措施七、CTF例题八、资源推荐 一、什么是SQL注入&#xff1f; SQL注入是一种通过用户输入构造恶意…...

STM32 低功耗模式

目录 背景 低功耗模式 睡眠模式 进入睡眠模式 退出睡眠模式 停止模式 进入停止模式 退出停止模式 待机模式 进入待机模式 退出待机模式 程序 睡眠模式 休眠模式配置 进入休眠模式 退出睡眠模式 停止模式 停止模式配置 进入停止模式 退出停止模式 待机模式…...

网络安全架构战略 网络安全体系结构

本节书摘来自异步社区《网络安全体系结构》一书中的第1章&#xff0c;第1.4节&#xff0c;作者【美】Sean Convery 1.4 一切皆为目标 网络安全体系结构 当前的大型网络存在着惊人的相互依赖性&#xff0c;作为一名网络安全设计师&#xff0c;对这一点必须心知肚明。Internet就…...

【算法】回溯算法

回溯算法 什么是回溯 人生无时不在选择。在选择的路口&#xff0c;你该如何抉择 ..... 回溯&#xff1a; 是一种选优搜索法&#xff0c;又称为试探法&#xff0c;按选优条件向前搜索&#xff0c;以达到目标。但当探索到某一步时&#xff0c;发现原先选择并不优或达不到目标&am…...

AI大模型(如GPT、BERT等)可以通过自然语言处理(NLP)和机器学习技术,显著提升测试效率

在软件测试中,AI大模型(如GPT、BERT等)可以通过自然语言处理(NLP)和机器学习技术,显著提升测试效率。以下是几个具体的应用场景及对应的代码实现示例: 1. 自动生成测试用例 AI大模型可以根据需求文档或用户故事自动生成测试用例。 代码示例(使用 OpenAI GPT API): …...

Centos安装php-8.0.24.tar

查看系统环境 cat /etc/redhat-release 预先安装必要的依赖 yum install -y \ wget \ gcc \ gcc-c \ autoconf \ automake \ libtool \ make \ libxml2 \ libxml2-devel \ openssl \ openssl-devel \ sqlite-devel yum update 1、下载解压 cd /data/ wget https:/…...