using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
namespace Dpz.Core.Entity.Base;
public static class PropertyAccessor
{
private static readonly ConcurrentDictionary<
Type,
ConcurrentDictionary<string, PropertyInfo?>
> PropertiesKeysCache = new();
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropertiesCache = new();
private readonly record struct TypePropertyKey(Type Type, string PropertyName);
private static readonly ConcurrentDictionary<
TypePropertyKey,
PropertyInfo?
> PropertyByNameCache = new();
public static PropertyInfo[] GetProperties(Type type)
{
return PropertiesCache.GetOrAdd(
type,
t => t.GetProperties(BindingFlags.Public | BindingFlags.Instance)
);
}
public static PropertyInfo? GetProperty(Type? type, string propertyName)
{
if (type == null)
{
return null;
}
return PropertyByNameCache.GetOrAdd(
new TypePropertyKey(type, propertyName),
key =>
key.Type.GetProperty(key.PropertyName, BindingFlags.Public | BindingFlags.Instance)
);
}
private static class MemberAccessor<T>
{
internal static readonly ConcurrentDictionary<
string,
Lazy<Action<T, object?>>
> SetterCache = new();
internal static readonly ConcurrentDictionary<string, Lazy<Func<T, object?>>> GetterCache =
new();
}
public static Action<T, object?>? GetSetter<T>(string propertyName)
{
var property = GetProperty<T>(propertyName);
if (property == null || !property.CanWrite)
{
return null;
}
if (MemberAccessor<T>.SetterCache.TryGetValue(propertyName, out var cacheValue))
{
return cacheValue.Value;
}
var lazyValue = MemberAccessor<T>.SetterCache.GetOrAdd(
propertyName,
_ => new Lazy<Action<T, object?>>(
() => CreateSetterExpressionTree<T>(property),
LazyThreadSafetyMode.ExecutionAndPublication
)
);
return lazyValue.Value;
}
public static Func<T, object?>? GetGetter<T>(string propertyName)
{
var property = GetProperty<T>(propertyName);
if (property == null || !property.CanRead)
{
return null;
}
if (MemberAccessor<T>.GetterCache.TryGetValue(propertyName, out var cacheValue))
{
return cacheValue.Value;
}
var lazyValue = MemberAccessor<T>.GetterCache.GetOrAdd(
propertyName,
_ => new Lazy<Func<T, object?>>(
() => CreateGetterExpressionTree<T>(property),
LazyThreadSafetyMode.ExecutionAndPublication
)
);
return lazyValue.Value;
}
private static Action<T, object?> CreateSetterExpressionTree<T>(PropertyInfo property)
{
var target = Expression.Parameter(typeof(T), "__q");
var value = Expression.Parameter(typeof(object), "__q2");
var convert = Expression.Convert(value, property.PropertyType);
var propertyAccess = Expression.Property(target, property);
var assign = Expression.Assign(propertyAccess, convert);
var lambda = Expression.Lambda<Action<T, object?>>(assign, target, value);
return lambda.Compile();
}
private static Func<T, object?> CreateGetterExpressionTree<T>(PropertyInfo property)
{
var target = Expression.Parameter(typeof(T), "__q");
var propertyAccess = Expression.Property(target, property);
var convert = Expression.Convert(propertyAccess, typeof(object));
var lambda = Expression.Lambda<Func<T, object?>>(convert, target);
return lambda.Compile();
}
private static PropertyInfo? GetProperty<T>(string propertyName)
{
var typeProperties = PropertiesKeysCache.GetOrAdd(
typeof(T),
_ => new ConcurrentDictionary<string, PropertyInfo?>()
);
if (typeProperties.TryGetValue(propertyName, out var propertyInfo))
{
return propertyInfo;
}
var property = GetProperties(typeof(T)).FirstOrDefault(p => p.Name == propertyName);
typeProperties.TryAdd(propertyName, property);
return property;
}
}
⚠⚠ 以下内容为AI分析的结果,请根据实际情况进行判断。
这是一个高性能的属性访问器工具类,主要用于通过反射动态访问对象的属性,并使用多种缓存机制来优化性能。让我详细解释一下:
核心功能
这个类提供了以下主要功能:
- 获取类型的所有属性
- 根据属性名获取特定属性
- 动态生成属性的Setter和Getter方法
缓存机制
代码使用了多层缓存来提升性能:
// 1. 缓存类型的所有属性
private static readonly ConcurrentDictionary<Type, PropertyInfo[]> PropertiesCache = new();
// 2. 缓存类型-属性名映射
private static readonly ConcurrentDictionary<Type, ConcurrentDictionary<string, PropertyInfo?>> PropertiesKeysCache = new();
// 3. 缓存单个属性查询
private static readonly ConcurrentDictionary<TypePropertyKey, PropertyInfo?> PropertyByNameCache = new();
// 4. 为每个泛型类型T缓存Setter和Getter
private static class MemberAccessor<T>
{
internal static readonly ConcurrentDictionary<string, Lazy<Action<T, object?>>> SetterCache = new();
internal static readonly ConcurrentDictionary<string, Lazy<Func<T, object?>>> GetterCache = new();
}
主要方法解析
1. GetProperties
public static PropertyInfo[] GetProperties(Type type)
获取类型的所有公共实例属性,结果会被缓存。
2. GetProperty
public static PropertyInfo? GetProperty(Type? type, string propertyName)
根据类型和属性名获取特定属性,使用TypePropertyKey作为缓存键。
3. GetSetter/GetGetter
public static Action<T, object?>? GetSetter<T>(string propertyName)
public static Func<T, object?>? GetGetter<T>(string propertyName)
这两个方法是核心功能,它们:
- 首先检查属性是否存在且可写/可读
- 使用
Lazy<T>确保线程安全的延迟初始化 - 通过表达式树动态生成高性能的访问器
表达式树生成
Setter生成:
private static Action<T, object?> CreateSetterExpressionTree<T>(PropertyInfo property)
{
var target = Expression.Parameter(typeof(T), "__q"); // 目标对象参数
var value = Expression.Parameter(typeof(object), "__q2"); // 值参数
var convert = Expression.Convert(value, property.PropertyType); // 类型转换
var propertyAccess = Expression.Property(target, property); // 属性访问
var assign = Expression.Assign(propertyAccess, convert); // 赋值操作
var lambda = Expression.Lambda<Action<T, object?>>(assign, target, value);
return lambda.Compile(); // 编译为委托
}
Getter生成:
private static Func<T, object?> CreateGetterExpressionTree<T>(PropertyInfo property)
{
var target = Expression.Parameter(typeof(T), "__q"); // 目标对象参数
var propertyAccess = Expression.Property(target, property); // 属性访问
var convert = Expression.Convert(propertyAccess, typeof(object)); // 转换为object
var lambda = Expression.Lambda<Func<T, object?>>(convert, target);
return lambda.Compile(); // 编译为委托
}
设计优势
- 高性能:使用表达式树生成的委托比直接反射快很多
- 线程安全:使用
ConcurrentDictionary和Lazy<T>确保多线程环境下的安全性 - 内存效率:多层缓存避免重复计算和对象创建
- 类型安全:泛型设计提供编译时类型检查
使用场景
这个工具类通常用于:
- ORM框架中的对象属性映射
- 序列化/反序列化
- 动态对象操作
- 数据绑定场景
总的来说,这是一个设计精良的高性能反射工具类,通过多层缓存和表达式树技术,在保持灵活性的同时最大化了性能。
AI 正在分析代码…
评论加载中...