A:common基础功能及测试
This commit is contained in:
1 parent
9ffa70acde
commit
237cbd8788
11 files changed
+5929
-32
No files matched your search
@@ -0,0 +1,525 @@
|
||||
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
|
||||
}
|
||||
Reference in new issue
Block a user