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

使用表达式树实现字符串形式的表达式访问对象属性

使用表达式树实现字符串形式的表达式访问对象属性

在C#中,使用表达式树(Expression Trees)可以动态地构建和编译代码,这使得我们可以通过字符串形式的表达式来访问对象的属性。下面是实现这一功能的几种方法:

1. 基本实现方式

using System;
using System.Linq.Expressions;
using System.Reflection;public static class PropertyAccessor
{
public static Func<T, object> CreatePropertyGetter<T>(string propertyName)
{
var parameter = Expression.Parameter(typeof(T), "x");
Expression property = Expression.Property(parameter, propertyName);
Expression conversion = Expression.Convert(property, typeof(object));
return Expression.Lambda<Func<T, object>>(conversion, parameter).Compile();
}public static Action<T, object> CreatePropertySetter<T>(string propertyName)
{
var parameter = Expression.Parameter(typeof(T), "x");
var valueParameter = Expression.Parameter(typeof(object), "value");
var property = Expression.Property(parameter, propertyName);
var assignment = Expression.Assign(
property,
Expression.Convert(valueParameter, property.Type));
return Expression.Lambda<Action<T, object>>(assignment, parameter, valueParameter).Compile();
}
}

使用示例

public class Person
{
public string Name { get; set; }
public int Age { get; set; }
}// 使用
var person = new Person { Name = "Alice", Age = 30 };// 获取属性
var getName = PropertyAccessor.CreatePropertyGetter<Person>("Name");
Console.WriteLine(getName(person)); // 输出 "Alice"// 设置属性
var setAge = PropertyAccessor.CreatePropertySetter<Person>("Age");
setAge(person, 35);
Console.WriteLine(person.Age); // 输出 35

2. 支持嵌套属性访问

public static Func<T, object> CreateNestedPropertyGetter<T>(string propertyPath)
{
var parameter = Expression.Parameter(typeof(T), "x");
Expression property = parameter;foreach (var member in propertyPath.Split('.'))
{
property = Expression.PropertyOrField(property, member);
}Expression conversion = Expression.Convert(property, typeof(object));
return Expression.Lambda<Func<T, object>>(conversion, parameter).Compile();
}

使用示例

public class Address
{
public string City { get; set; }
}public class Person
{
public string Name { get; set; }
public Address HomeAddress { get; set; }
}// 使用
var person = new Person
{
Name = "Bob",
HomeAddress = new Address { City = "New York" }
};var getCity = PropertyAccessor.CreateNestedPropertyGetter<Person>("HomeAddress.City");
Console.WriteLine(getCity(person)); // 输出 "New York"

3. 更完整的表达式解析

对于更复杂的表达式(如数组索引、方法调用等),可以使用 System.Linq.Dynamic.Core 库:

// 安装 NuGet 包: System.Linq.Dynamic.Coreusing System.Linq.Dynamic.Core;public static class DynamicAccessor
{
public static Func<T, object> CreateExpression<T>(string expression)
{
var parameter = Expression.Parameter(typeof(T), "x");
var lambda = DynamicExpressionParser.ParseLambda(
new[] { parameter },
typeof(object),
expression);
return (Func<T, object>)lambda.Compile();
}
}

使用示例

public class Company
{
public List<Person> Employees { get; set; } = new List<Person>();
}// 使用
var company = new Company
{
Employees = new List<Person>
{
new Person { Name = "Alice", Age = 30 },
new Person { Name = "Bob", Age = 35 }
}
};var getFirstEmployeeName = DynamicAccessor.CreateExpression<Company>("Employees.Name");
Console.WriteLine(getFirstEmployeeName(company)); // 输出 "Alice"

4. 性能考虑

表达式树在第一次构建和编译时会有性能开销,但编译后的委托执行速度与直接编写的代码几乎相同。如果需要在循环中重复使用,应该缓存编译后的委托。

private static Dictionary<string, Func<T, object>> _getterCache = new Dictionary<string, Func<T, object>>();public static Func<T, object> GetCachedPropertyGetter<T>(string propertyName)
{
if (!_getterCache.TryGetValue(propertyName, out var getter))
{
getter = CreatePropertyGetter<T>(propertyName);
_getterCache[propertyName] = getter;
}
return getter;
}

注意事项

  1. 属性名称或路径错误会抛出异常,可以添加错误处理
  2. 对于私有成员,需要设置适当的绑定标志
  3. 表达式树不支持所有C#语法,复杂逻辑可能需要使用其他方法

以上方法提供了灵活的方式来通过字符串表达式访问对象属性,可以根据具体需求选择适合的实现方式。

http://www.dtcms.com/a/528829.html

相关文章:

  • SFT(有监督微调)、RLHF(强化学习)、RAG(检索增强⽣成)
  • 网页设计模板图片代码seo岗位职责
  • wordpress开发网站html如何建网站
  • 深度学习核心模型详解:CNN与RNN
  • 哈尔滨整站如何做网站流量买卖
  • 智能制造知识图谱的建设路线
  • IPIDEA实现数据采集自动化:高效自动化采集方案
  • 网站开发认证考试wordpress目录 读写权限设置
  • 【51单片机】【protues仿真】基于51单片机热敏电阻数字温度计数码管系统
  • Java基础与集合小压八股
  • 网站建设做网站需要多少钱?杭州网站建设公司有哪些
  • [ Redis ] SpringBoot集成使用Redis(补充)
  • GitHub等平台形成的开源文化正在重塑伊朗人
  • 贵州省建设厅网站造价工程信息网东港建站公司
  • UE5 蓝图-17:主 mainUI 界面蓝图,构成与尺寸分析;界面菜单栏里按钮 Ul_menuButtonsUl 蓝图的构成记录,
  • 公司企业网站免费建设网站建设需要技术
  • SQL MID() 函数详解
  • SQL187 每份试卷每月作答数和截止当月的作答总数。
  • 三河建设局网站做学校网站用什么模版
  • 装修网站建设服务商wordpress 编辑图片无法显示
  • 建设网站要求有哪些营销型网站建设搭建方法
  • jQuery noConflict() 方法详解
  • JavaScript 性能优化系列(六)接口调用优化 - 6.4 错误重试策略:智能重试机制,提高请求成功率
  • 绘画基础知识学习
  • 自己的服务器做网站要备案做网站用到ps么
  • 第 4 篇:SSM 分布式落地:状态持久化与并行状态(含 Redis/MySQL 实战)
  • STM32全栈智慧鱼缸——硬件选型、接线图、软件流程图与完整源码
  • 【11408学习记录】考研数学概率论攻坚:事件的独立性与独立重复试验核心精讲
  • linux下文件操作函数
  • 电商网站建设与维护意味着什么公众号登录怎么退出