Files
sharp-basic/src/Sharp/Common/Utils/ReflectionHelper.cs
T
2025-12-30 09:17:25 +08:00

521 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Collections.Concurrent;
using System.Linq.Expressions;
using System.Reflection;
namespace Common.Utils;
/// <summary>
/// 属性访问器(用于缓存,提高反射性能)
/// </summary>
/// <typeparam name="T">类型</typeparam>
internal class PropertyAccessor<T>
{
public Func<T, object?>? Getter { get; set; }
public Action<T, object?>? Setter { get; set; }
public PropertyInfo PropertyInfo { get; set; }
public PropertyAccessor(PropertyInfo propertyInfo)
{
PropertyInfo = propertyInfo;
}
}
/// <summary>
/// 反射工具类
/// 提供类型扫描、属性访问、特性读取等功能,并通过缓存提高性能
/// </summary>
public static class ReflectionHelper
{
// 属性访问器缓存
private static readonly ConcurrentDictionary<Type, Dictionary<string, object>> PropertyAccessorCache = new();
// 特性缓存
private static readonly ConcurrentDictionary<MemberInfo, object[]> AttributeCache = new();
// 类型缓描
private static readonly ConcurrentDictionary<Assembly, Type[]> TypeCache = new();
#region 类型扫描
/// <summary>
/// 从程序集中获取所有类型
/// </summary>
/// <param name="assembly">程序集</param>
/// <param name="useCache">是否使用缓存(默认 true)</param>
/// <returns>类型数组</returns>
public static Type[] GetTypes(Assembly assembly, bool useCache = true)
{
if (useCache && TypeCache.TryGetValue(assembly, out var cachedTypes))
return cachedTypes;
var types = assembly.GetTypes();
if (useCache)
TypeCache.TryAdd(assembly, types);
return types;
}
/// <summary>
/// 从当前程序集中查找指定基类的所有子类
/// </summary>
/// <typeparam name="TBase">基类类型</typeparam>
/// <param name="includeAbstract">是否包含抽象类(默认 false)</param>
/// <returns>子类类型列表</returns>
public static List<Type> FindSubclassesOf<TBase>(bool includeAbstract = false)
{
return FindSubclassesOf(typeof(TBase), includeAbstract);
}
/// <summary>
/// 从当前程序集中查找指定基类的所有子类
/// </summary>
public static List<Type> FindSubclassesOf(Type baseType, bool includeAbstract = false)
{
var assembly = Assembly.GetCallingAssembly();
return GetTypes(assembly)
.Where(t => t.IsClass && baseType.IsAssignableFrom(t) && t != baseType)
.Where(t => includeAbstract || !t.IsAbstract)
.ToList();
}
/// <summary>
/// 从指定程序集中查找实现指定接口的所有类型
/// </summary>
/// <typeparam name="TInterface">接口类型</typeparam>
/// <param name="assembly">程序集</param>
/// <param name="includeAbstract">是否包含抽象类(默认 false)</param>
/// <returns>实现类型列表</returns>
public static List<Type> FindImplementationsOf<TInterface>(Assembly assembly, bool includeAbstract = false)
{
var interfaceType = typeof(TInterface);
return GetTypes(assembly)
.Where(t => t.IsClass && interfaceType.IsAssignableFrom(t) && t != interfaceType)
.Where(t => includeAbstract || !t.IsAbstract)
.ToList();
}
/// <summary>
/// 查找带有指定特性的所有类型
/// </summary>
/// <typeparam name="TAttribute">特性类型</typeparam>
/// <param name="assembly">程序集</param>
/// <param name="inherit">是否搜索继承链(默认 true)</param>
/// <returns>类型列表</returns>
public static List<Type> FindTypesWithAttribute<TAttribute>(Assembly assembly, bool inherit = true)
where TAttribute : Attribute
{
return GetTypes(assembly)
.Where(t => t.GetCustomAttribute<TAttribute>(inherit) != null)
.ToList();
}
#endregion
#region 属性访问(高性能)
/// <summary>
/// 获取属性值(使用缓存的访问器,比直接反射快)
/// </summary>
public static object? GetPropertyValue<T>(T obj, string propertyName)
{
var accessor = GetPropertyAccessor<T>(propertyName);
return accessor?.Getter?.Invoke(obj);
}
/// <summary>
/// 设置属性值(使用缓存的访问器)
/// </summary>
public static void SetPropertyValue<T>(T obj, string propertyName, object? value)
{
var accessor = GetPropertyAccessor<T>(propertyName);
accessor?.Setter?.Invoke(obj, value);
}
/// <summary>
/// 获取属性访问器(内部使用表达式树生成,首次慢,后续快)
/// </summary>
private static PropertyAccessor<T>? GetPropertyAccessor<T>(string propertyName)
{
var type = typeof(T);
var cache = PropertyAccessorCache.GetOrAdd(type, _ => new Dictionary<string, object>());
lock (cache)
{
if (cache.TryGetValue(propertyName, out var cachedAccessor))
return (PropertyAccessor<T>)cachedAccessor;
var propertyInfo = type.GetProperty(propertyName, BindingFlags.Public | BindingFlags.Instance);
if (propertyInfo == null)
return null;
var accessor = new PropertyAccessor<T>(propertyInfo);
// 使用表达式树生成 Getter
if (propertyInfo.CanRead)
{
var instance = Expression.Parameter(type, "instance");
var property = Expression.Property(instance, propertyInfo);
var convert = Expression.Convert(property, typeof(object));
accessor.Getter = Expression.Lambda<Func<T, object?>>(convert, instance).Compile();
}
// 使用表达式树生成 Setter
if (propertyInfo.CanWrite)
{
var instance = Expression.Parameter(type, "instance");
var value = Expression.Parameter(typeof(object), "value");
var convert = Expression.Convert(value, propertyInfo.PropertyType);
var property = Expression.Property(instance, propertyInfo);
var assign = Expression.Assign(property, convert);
accessor.Setter = Expression.Lambda<Action<T, object?>>(assign, instance, value).Compile();
}
cache[propertyName] = accessor;
return accessor;
}
}
/// <summary>
/// 获取所有属性名称
/// </summary>
public static List<string> GetPropertyNames<T>(BindingFlags flags = BindingFlags.Public | BindingFlags.Instance)
{
return typeof(T).GetProperties(flags).Select(p => p.Name).ToList();
}
/// <summary>
/// 获取所有属性信息
/// </summary>
public static PropertyInfo[] GetProperties<T>(BindingFlags flags = BindingFlags.Public | BindingFlags.Instance)
{
return typeof(T).GetProperties(flags);
}
#endregion
#region 特性读取(带缓存)
/// <summary>
/// 获取类型的特性(带缓存)
/// </summary>
public static TAttribute? GetAttribute<TAttribute>(Type type, bool inherit = true)
where TAttribute : Attribute
{
var attributes = GetAttributes<TAttribute>(type, inherit);
return attributes.FirstOrDefault();
}
/// <summary>
/// 获取类型的所有指定特性(带缓存)
/// </summary>
public static TAttribute[] GetAttributes<TAttribute>(Type type, bool inherit = true)
where TAttribute : Attribute
{
var cached = AttributeCache.GetOrAdd(type, _ => type.GetCustomAttributes(inherit).ToArray());
return cached.OfType<TAttribute>().ToArray();
}
/// <summary>
/// 获取成员的特性(带缓存)
/// </summary>
public static TAttribute? GetAttribute<TAttribute>(MemberInfo member, bool inherit = true)
where TAttribute : Attribute
{
var attributes = GetAttributes<TAttribute>(member, inherit);
return attributes.FirstOrDefault();
}
/// <summary>
/// 获取成员的所有指定特性(带缓存)
/// </summary>
public static TAttribute[] GetAttributes<TAttribute>(MemberInfo member, bool inherit = true)
where TAttribute : Attribute
{
var cached = AttributeCache.GetOrAdd(member, _ => member.GetCustomAttributes(inherit).ToArray());
return cached.OfType<TAttribute>().ToArray();
}
/// <summary>
/// 判断类型是否有指定特性
/// </summary>
public static bool HasAttribute<TAttribute>(Type type, bool inherit = true)
where TAttribute : Attribute
{
return GetAttribute<TAttribute>(type, inherit) != null;
}
/// <summary>
/// 判断成员是否有指定特性
/// </summary>
public static bool HasAttribute<TAttribute>(MemberInfo member, bool inherit = true)
where TAttribute : Attribute
{
return GetAttribute<TAttribute>(member, inherit) != null;
}
#endregion
#region 创建实例
/// <summary>
/// 创建类型实例(使用无参构造函数)
/// </summary>
public static T? CreateInstance<T>() where T : class
{
return Activator.CreateInstance<T>();
}
/// <summary>
/// 创建类型实例(使用无参构造函数)
/// </summary>
public static object? CreateInstance(Type type)
{
return Activator.CreateInstance(type);
}
/// <summary>
/// 创建类型实例(使用有参构造函数)
/// </summary>
public static object? CreateInstance(Type type, params object[] args)
{
return Activator.CreateInstance(type, args);
}
/// <summary>
/// 尝试创建类型实例
/// </summary>
public static bool TryCreateInstance<T>(out T? instance) where T : class
{
try
{
instance = CreateInstance<T>();
return instance != null;
}
catch
{
instance = null;
return false;
}
}
#endregion
#region 属性复制
/// <summary>
/// 将源对象的属性值复制到目标对象(同名属性)
/// </summary>
/// <typeparam name="TSource">源类型</typeparam>
/// <typeparam name="TTarget">目标类型</typeparam>
/// <param name="source">源对象</param>
/// <param name="target">目标对象</param>
/// <param name="ignoreCase">是否忽略属性名大小写(默认 false)</param>
public static void CopyProperties<TSource, TTarget>(TSource source, TTarget target, bool ignoreCase = false)
{
if (source == null || target == null)
return;
var sourceType = typeof(TSource);
var targetType = typeof(TTarget);
var sourceProperties = sourceType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanRead)
.ToList();
var targetProperties = targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.CanWrite)
.ToDictionary(
p => p.Name,
p => p,
ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal
);
foreach (var sourceProp in sourceProperties)
if (targetProperties.TryGetValue(sourceProp.Name, out var targetProp))
// 检查类型是否兼容
if (targetProp.PropertyType.IsAssignableFrom(sourceProp.PropertyType))
{
var value = sourceProp.GetValue(source);
targetProp.SetValue(target, value);
}
}
/// <summary>
/// 创建目标类型实例并复制属性
/// </summary>
public static TTarget? MapTo<TSource, TTarget>(TSource source, bool ignoreCase = false)
where TTarget : class, new()
{
if (source == null)
return null;
var target = new TTarget();
CopyProperties(source, target, ignoreCase);
return target;
}
#endregion
#region 方法调用
/// <summary>
/// 调用对象的方法
/// </summary>
/// <param name="obj">对象实例</param>
/// <param name="methodName">方法名</param>
/// <param name="parameters">参数</param>
/// <returns>方法返回值</returns>
public static object? InvokeMethod(object obj, string methodName, params object[] parameters)
{
var type = obj.GetType();
var method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
if (method == null)
throw new InvalidOperationException($"Method '{methodName}' not found on type '{type.FullName}'");
return method.Invoke(obj, parameters);
}
/// <summary>
/// 调用静态方法
/// </summary>
public static object? InvokeStaticMethod(Type type, string methodName, params object[] parameters)
{
var method = type.GetMethod(methodName, BindingFlags.Public | BindingFlags.Static);
if (method == null)
throw new InvalidOperationException($"Static method '{methodName}' not found on type '{type.FullName}'");
return method.Invoke(null, parameters);
}
#endregion
#region 类型判断
/// <summary>
/// 判断类型是否为可空类型
/// </summary>
public static bool IsNullableType(Type type)
{
return Nullable.GetUnderlyingType(type) != null;
}
/// <summary>
/// 获取可空类型的基础类型
/// </summary>
public static Type GetUnderlyingType(Type type)
{
return Nullable.GetUnderlyingType(type) ?? type;
}
/// <summary>
/// 判断类型是否为值类型
/// </summary>
public static bool IsValueType(Type type)
{
return type.IsValueType;
}
/// <summary>
/// 判断类型是否为引用类型
/// </summary>
public static bool IsReferenceType(Type type)
{
return !type.IsValueType;
}
/// <summary>
/// 判断类型是否为数字类型
/// </summary>
public static bool IsNumericType(Type type)
{
type = GetUnderlyingType(type);
return type == typeof(byte) || type == typeof(sbyte) ||
type == typeof(short) || type == typeof(ushort) ||
type == typeof(int) || type == typeof(uint) ||
type == typeof(long) || type == typeof(ulong) ||
type == typeof(float) || type == typeof(double) ||
type == typeof(decimal);
}
/// <summary>
/// 判断类型是否为集合类型
/// </summary>
public static bool IsCollectionType(Type type)
{
return type.IsArray ||
(type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) ||
type.GetInterfaces().Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>));
}
#endregion
#region 泛型操作
/// <summary>
/// 判断类型是否为泛型类型
/// </summary>
public static bool IsGenericType(Type type)
{
return type.IsGenericType;
}
/// <summary>
/// 获取泛型参数类型
/// </summary>
public static Type[] GetGenericArguments(Type type)
{
return type.GetGenericArguments();
}
/// <summary>
/// 构造泛型类型(例如:List<> + int => List<int>)
/// </summary>
public static Type MakeGenericType(Type genericTypeDefinition, params Type[] typeArguments)
{
return genericTypeDefinition.MakeGenericType(typeArguments);
}
#endregion
#region 缓存管理
/// <summary>
/// 清除所有缓存
/// </summary>
public static void ClearCache()
{
PropertyAccessorCache.Clear();
AttributeCache.Clear();
TypeCache.Clear();
}
/// <summary>
/// 清除属性访问器缓存
/// </summary>
public static void ClearPropertyAccessorCache()
{
PropertyAccessorCache.Clear();
}
/// <summary>
/// 清除特性缓存
/// </summary>
public static void ClearAttributeCache()
{
AttributeCache.Clear();
}
/// <summary>
/// 清除类型缓存
/// </summary>
public static void ClearTypeCache()
{
TypeCache.Clear();
}
#endregion
}