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

FastProperty 高效的属性读写设置

  FastProperty 是一个设计精良、性能优异的工具类,很好地解决了批量操作中属性访问的性能问题,核心逻辑经得起推敲。对于 EFCore.BulkExtensions 的主要应用场景,它已经足够 “完美”。

/// <summary>
/// 使用反射初始化类型的类
/// </summary>
public class FastProperty
{// 用于缓存FastProperty实例的并发字典,确保线程安全private static readonly ConcurrentDictionary<PropertyInfo, FastProperty> FastPropertyCache = new();/// <summary>/// 获取或创建用于读写指定属性的FastProperty实例/// </summary>/// <param name="property">要获取FastProperty实例的属性</param>/// <returns>/// 新的或已存在的缓存中的FastProperty实例/// </returns>public static FastProperty GetOrCreate(PropertyInfo property){return FastPropertyCache.GetOrAdd(property, p => new FastProperty(p));}// 获取属性值的委托private Func<object, object>? _getDelegate;// 设置属性值的委托private Action<object, object>? _setDelegate;/// <summary>/// FastProperty的构造函数/// </summary>/// <param name="property">属性信息</param>private FastProperty(PropertyInfo property){Property = property;InitializeGet();InitializeSet();}/// <summary>/// 初始化属性设置委托/// </summary>private void InitializeSet(){var instance = Expression.Parameter(typeof(object), "instance");var value = Expression.Parameter(typeof(object), "value");if (Property.DeclaringType is null){throw new ArgumentException("无法从属性中确定声明类型(DeclaringType)");}// 根据属性声明类型是值类型还是引用类型,选择不同的转换方式UnaryExpression instanceCast = (!Property.DeclaringType?.IsValueType ?? false)? Expression.TypeAs(instance, Property.DeclaringType!): Expression.Convert(instance, Property.DeclaringType!);// 根据属性类型是值类型还是引用类型,选择不同的转换方式UnaryExpression valueCast = (!Property.PropertyType.IsValueType)? Expression.TypeAs(value, Property.PropertyType): Expression.Convert(value, Property.PropertyType);// 获取属性的set方法(支持非公共方法),处理继承自父类的属性场景var setter = Property.GetSetMethod(true) ?? Property.DeclaringType?.GetProperty(Property.Name)?.GetSetMethod(true);if (setter != null)// 编译表达式为设置属性的委托_setDelegate = Expression.Lambda<Action<object, object>>(Expression.Call(instanceCast, setter, valueCast), new ParameterExpression[] { instance, value }).Compile();}/// <summary>/// 初始化属性获取委托/// </summary>private void InitializeGet(){var instance = Expression.Parameter(typeof(object), "instance");if (Property.DeclaringType is null){throw new ArgumentException("无法从属性中确定声明类型(DeclaringType)");}// 根据属性声明类型是值类型还是引用类型,选择不同的转换方式UnaryExpression instanceCast = (!Property.DeclaringType.IsValueType)? Expression.TypeAs(instance, Property.DeclaringType): Expression.Convert(instance, Property.DeclaringType);// 获取属性的get方法(支持非公共方法),处理继承自父类的属性场景var getter = Property.GetGetMethod(true) ?? Property.DeclaringType.GetProperty(Property.Name)?.GetGetMethod(true);if (getter != null)// 编译表达式为获取属性的委托_getDelegate = Expression.Lambda<Func<object, object>>(Expression.TypeAs(Expression.Call(instanceCast, getter), typeof(object)), instance).Compile();}public PropertyInfo Property { get; set; }/// <summary>/// 返回属性值/// </summary>/// <param name="instance">实例对象</param>/// <returns>属性值</returns>public object? Get(object instance) => instance == default || _getDelegate is null ? default : _getDelegate(instance);/// <summary>/// 设置属性值/// </summary>/// <param name="instance">实例对象</param>/// <param name="value">要设置的值</param>public void Set(object instance, object? value){if (value != default && _setDelegate is not null){_setDelegate(instance, value);}}
}

使用示例:

var property = typeof(MyEntity).GetProperty("Id");
var fastProp = FastProperty.GetOrCreate(property);
var entity = new MyEntity { Id = Guid.NewGuid() };// 高效获取属性值
var id = fastProp.Get(entity); 
// 高效设置属性值
fastProp.Set(entity, Guid.NewGuid());

总结

FastProperty 是 EFCore.BulkExtensions 性能优化的关键组件之一,它通过:

  1. 表达式树编译委托替代反射,解决了反射性能瓶颈;
  2. 线程安全缓存避免重复计算,降低初始化开销;
  3. 简洁接口简化属性访问逻辑,支撑了批量操作中的高频属性读写需求。

 

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

相关文章:

  • 【开题答辩全过程】以 基于Java的失物招领平台为例,包含答辩的问题和答案
  • 【7/20】前后端整合:Vue.js 调用 Express API,操作 MongoDB 数据,实现用户管理系统
  • 【8/20】用户认证基础:JWT 在 Express 中的实现,实现安全登录
  • 独立站有哪些建站工具
  • Linux 终端常用快捷键整理
  • 跨域的两种解决方法
  • 小程序中获取年月日时分的组件
  • Redis热升级秘籍:零停机迁移方案与工具链
  • 时序数据库选型指南深度解析IoTDB架构设计与性能对比
  • springboot超市管理系统的设计与实现(代码+数据库+LW)
  • 让Trae写一个AI的api中继服务
  • 跨国制造业SD-WAN:延迟下降78%,运维成本下降53%
  • MySQL服务启动不成功的可能解决方法
  • 硬解码出现画面回退分析
  • P1068 [NOIP 2009 普及组] 分数线划定-普及-
  • 用python语言如何排大小
  • pycharm连接GitHub,怎么配置 SSH 密钥并改用 SSH 连接
  • ​​[硬件电路-265]:电源系统要考虑的因素包括:不同的输出电压、隔离防干扰、防反、防浪涌、电压可调、电源开关、电池、可充电、低纹波、低噪声、防波动等
  • 【开题答辩全过程】以 基于Python的电影推荐系统为例,包含答辩的问题和答案
  • 格拉姆角场(Gramian Angular Field, GAF)详解
  • 前端开发工具Vue有哪些?常用Vue前端开发工具推荐、Vue开发工具对比与最佳实践分享
  • 基于vue的幼儿园健康管理系统0fz0y(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • 第69课 分类任务: 基于BERT训练情感分类与区别二分类本质思考
  • Mysql杂志(二十)——MyISAM索引结构与B树B+树
  • Java 大视界 -- 基于 Java 的大数据实时流处理在金融高频交易数据分析中的应用
  • BonkFun 推出 USD1:Meme 币玩法的新入口
  • flutter在包含ListVIew的滚动列表页面中监听手势
  • Redis 三种集群模式详解
  • 打开hot100
  • Ant-Design Table中使用 AStatisticCountdown倒计时,鼠标在表格上移动时倒计时被重置