UNIVPLMDataIntegration/Admin.NET/Admin.NET.Core/Utils/ReflectionHelper.cs
zuohuaijun 77491355f2 😎调整类名
2025-06-16 01:03:22 +08:00

1031 lines
36 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.

// Admin.NET 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。使用本项目应遵守相关法律法规和许可证的要求。
//
// 本项目主要遵循 MIT 许可证和 Apache 许可证(版本 2.0)进行分发和使用。许可证位于源代码树根目录中的 LICENSE-MIT 和 LICENSE-APACHE 文件。
//
// 不得利用本项目从事危害国家安全、扰乱社会秩序、侵犯他人合法权益等法律法规禁止的活动!任何基于本项目二次开发而产生的一切法律纠纷和责任,我们不承担任何责任!
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using System.Runtime.Loader;
using SysReflection = System.Reflection.IntrospectionExtensions;
namespace Admin.NET.Core;
/// <summary>
/// 反射帮助类
/// 提供程序集、类型、属性等反射操作的工具方法
/// </summary>
public static class ReflectionHelper
{
#region
/// <summary>
/// 获取应用程序的入口程序集
/// </summary>
/// <returns>入口程序集,如果无法确定则返回 null</returns>
public static Assembly? GetEntryAssembly()
{
return Assembly.GetEntryAssembly();
}
/// <summary>
/// 获取入口程序集的名称
/// </summary>
/// <returns>程序集名称,如果无法获取则返回 null</returns>
public static string? GetEntryAssemblyName()
{
return GetEntryAssembly()?.GetName().Name;
}
/// <summary>
/// 获取入口程序集的版本信息
/// </summary>
/// <returns>程序集版本,如果无法获取则返回 null</returns>
public static Version? GetEntryAssemblyVersion()
{
return GetEntryAssembly()?.GetName().Version;
}
/// <summary>
/// 获取指定目录下的程序集文件路径
/// </summary>
/// <param name="folderPath">要搜索的文件夹路径</param>
/// <param name="searchOption">搜索选项(是否包含子目录)</param>
/// <returns>程序集文件路径集合(.dll 和 .exe 文件)</returns>
/// <exception cref="ArgumentException">当文件夹路径为空或 null 时</exception>
public static IEnumerable<string> GetAssemblyFiles(string folderPath, SearchOption searchOption)
{
ArgumentException.ThrowIfNullOrWhiteSpace(folderPath);
return Directory
.EnumerateFiles(folderPath, "*.*", searchOption)
.Where(s => s.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) ||
s.EndsWith(".exe", StringComparison.OrdinalIgnoreCase));
}
/// <summary>
/// 从指定目录加载所有程序集
/// </summary>
/// <param name="folderPath">要搜索的文件夹路径</param>
/// <param name="searchOption">搜索选项(是否包含子目录)</param>
/// <returns>加载的程序集列表</returns>
/// <exception cref="ArgumentException">当文件夹路径为空或 null 时</exception>
public static List<Assembly> LoadAssemblies(string folderPath, SearchOption searchOption)
{
ArgumentException.ThrowIfNullOrWhiteSpace(folderPath);
return [.. GetAssemblyFiles(folderPath, searchOption).Select(AssemblyLoadContext.Default.LoadFromAssemblyPath)];
}
/// <summary>
/// 获取当前应用程序域中加载的所有程序集
/// </summary>
/// <returns>已加载的程序集集合</returns>
public static IEnumerable<Assembly> GetAllAssemblies()
{
return AssemblyLoadContext.Default.Assemblies;
}
/// <summary>
/// 获取所有被引用的程序集(递归获取所有依赖项)
/// </summary>
/// <param name="skipSystemAssemblies">是否跳过系统程序集(默认为 true</param>
/// <returns>被引用的程序集集合</returns>
public static IEnumerable<Assembly> GetAllReferencedAssemblies(bool skipSystemAssemblies = true)
{
var rootAssembly = Assembly.GetEntryAssembly();
rootAssembly ??= Assembly.GetCallingAssembly();
HashSet<Assembly> returnAssemblies = new(new AssemblyEquality());
HashSet<string> loadedAssemblies = [];
Queue<Assembly> assembliesToCheck = new();
assembliesToCheck.Enqueue(rootAssembly);
if (skipSystemAssemblies && IsSystemAssembly(rootAssembly))
{
if (IsValid(rootAssembly))
{
_ = returnAssemblies.Add(rootAssembly);
}
}
while (assembliesToCheck.Count != 0)
{
var assemblyToCheck = assembliesToCheck.Dequeue();
foreach (var reference in assemblyToCheck.GetReferencedAssemblies())
{
if (loadedAssemblies.Contains(reference.FullName))
{
continue;
}
var assembly = Assembly.Load(reference);
if (skipSystemAssemblies && IsSystemAssembly(assembly))
{
continue;
}
assembliesToCheck.Enqueue(assembly);
_ = loadedAssemblies.Add(reference.FullName);
if (IsValid(assembly))
{
_ = returnAssemblies.Add(assembly);
}
}
}
var asmsInBaseDir = Directory.EnumerateFiles(AppContext.BaseDirectory, "*.dll", new EnumerationOptions
{
RecurseSubdirectories = true
});
foreach (var assemblyPath in asmsInBaseDir)
{
if (!IsManagedAssembly(assemblyPath))
{
continue;
}
var asmName = AssemblyName.GetAssemblyName(assemblyPath);
// 如果程序集已经加载过了就不再加载
if (returnAssemblies.Any(x => AssemblyName.ReferenceMatchesDefinition(x.GetName(), asmName)))
{
continue;
}
if (skipSystemAssemblies && IsSystemAssembly(assemblyPath))
{
continue;
}
var asm = TryLoadAssembly(assemblyPath);
if (asm is null)
{
continue;
}
if (!IsValid(asm))
{
continue;
}
if (skipSystemAssemblies && IsSystemAssembly(asm))
{
continue;
}
_ = returnAssemblies.Add(asm);
}
return [.. returnAssemblies];
}
/// <summary>
/// 获取符合条件名称的程序集
/// </summary>
/// <param name="prefix">前缀名</param>
/// <param name="suffix">后缀名</param>
/// <param name="contain">包含名</param>
/// <returns></returns>
public static IEnumerable<Assembly> GetEffectiveAssemblies(string prefix, string suffix, string contain)
{
ArgumentException.ThrowIfNullOrWhiteSpace(prefix);
ArgumentException.ThrowIfNullOrWhiteSpace(suffix);
ArgumentException.ThrowIfNullOrWhiteSpace(contain);
return GetAllAssemblies()
.Where(assembly => assembly.ManifestModule.Name.EndsWith(suffix, StringComparison.InvariantCultureIgnoreCase))
.Where(assembly => assembly.ManifestModule.Name.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
.Where(assembly => assembly.ManifestModule.Name.Contains(contain, StringComparison.InvariantCultureIgnoreCase))
.Distinct();
}
/// <summary>
/// 获取符合条件前后缀名称的程序集
/// </summary>
/// <param name="prefix">前缀名</param>
/// <param name="suffix">后缀名</param>
/// <returns></returns>
public static IEnumerable<Assembly> GetEffectivePatchAssemblies(string prefix, string suffix)
{
ArgumentException.ThrowIfNullOrWhiteSpace(prefix);
ArgumentException.ThrowIfNullOrWhiteSpace(suffix);
return GetAllAssemblies()
.Where(assembly => assembly.ManifestModule.Name.EndsWith(suffix, StringComparison.InvariantCultureIgnoreCase))
.Where(assembly => assembly.ManifestModule.Name.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase))
.Distinct();
}
/// <summary>
/// 获取符合条件包含名称的程序集
/// </summary>
/// <param name="contain">包含名</param>
/// <returns></returns>
public static IEnumerable<Assembly> GetEffectiveCenterAssemblies(string contain)
{
ArgumentException.ThrowIfNullOrWhiteSpace(contain);
return GetAllAssemblies()
.Where(assembly => assembly.ManifestModule.Name.Contains(contain, StringComparison.InvariantCultureIgnoreCase))
.Distinct();
}
/// <summary>
/// 获取框架程序集
/// </summary>
/// <returns></returns>
public static IEnumerable<Assembly> GetAdminNETAssemblies()
{
return GetEffectivePatchAssemblies("Admin.NET", "dll");
}
/// <summary>
/// 获取应用程序集
/// </summary>
/// <returns></returns>
public static IEnumerable<Assembly> GetApplicationAssemblies()
{
return GetEffectiveCenterAssemblies("Application");
}
/// <summary>
/// 获取框架应用程序集
/// </summary>
/// <returns></returns>
public static IEnumerable<Assembly> GetAdminNETApplicationAssemblies()
{
return GetEffectiveAssemblies("Admin.NET", "dll", "Application");
}
#endregion
#region
/// <summary>
/// 获取所有已加载程序集中的所有类型
/// </summary>
/// <returns>所有类型的集合</returns>
public static IEnumerable<Type> GetAllTypes()
{
return GetAllAssemblies()
.SelectMany(GetAllTypes)
.Distinct();
}
/// <summary>
/// 获取指定程序集中的所有类型(安全获取,处理加载异常)
/// </summary>
/// <param name="assembly">目标程序集</param>
/// <returns>程序集中的类型集合</returns>
/// <exception cref="ArgumentNullException">当程序集为 null 时</exception>
public static IEnumerable<Type> GetAllTypes(Assembly assembly)
{
ArgumentNullException.ThrowIfNull(assembly);
try
{
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException ex)
{
return ex.Types.Where(type => type != null)!;
}
}
/// <summary>
/// 获取框架框架程序集中的所有类型
/// </summary>
/// <returns>框架框架类型集合</returns>
public static IEnumerable<Type> GetAdminNETTypes()
{
return GetAdminNETAssemblies()
.SelectMany(GetAllTypes)
.Distinct();
}
/// <summary>
/// 获取应用程序集中的所有类型
/// </summary>
/// <returns>应用程序类型集合</returns>
public static IEnumerable<Type> GetApplicationTypes()
{
return GetApplicationAssemblies()
.SelectMany(GetAllTypes)
.Distinct();
}
/// <summary>
/// 获取框架应用程序集中的所有类型
/// </summary>
/// <returns>框架应用程序类型集合</returns>
public static IEnumerable<Type> GetAdminNETApplicationTypes()
{
return GetAdminNETApplicationAssemblies()
.SelectMany(GetAllTypes)
.Distinct();
}
#endregion
#region
/// <summary>
/// 检查给定类型是否实现或继承了指定的泛型类型
/// </summary>
/// <param name="givenType">要检查的类型</param>
/// <param name="genericType">泛型类型定义</param>
/// <returns>如果给定类型实现或继承了泛型类型则返回 true否则返回 false</returns>
public static bool IsAssignableToGenericType(Type givenType, Type genericType)
{
ArgumentNullException.ThrowIfNull(givenType);
ArgumentNullException.ThrowIfNull(genericType);
var givenTypeInfo = SysReflection.GetTypeInfo(givenType);
if (givenTypeInfo.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
{
return true;
}
foreach (var interfaceType in givenTypeInfo.GetInterfaces())
{
if (SysReflection.GetTypeInfo(interfaceType).IsGenericType && interfaceType.GetGenericTypeDefinition() == genericType)
{
return true;
}
}
return givenTypeInfo.BaseType != null && IsAssignableToGenericType(givenTypeInfo.BaseType, genericType);
}
/// <summary>
/// 获取给定类型实现的所有泛型类型
/// </summary>
/// <param name="givenType">要检查的类型</param>
/// <param name="genericType">泛型类型定义</param>
/// <returns>实现的泛型类型列表</returns>
public static List<Type> GetImplementedGenericTypes(Type givenType, Type genericType)
{
ArgumentNullException.ThrowIfNull(givenType);
ArgumentNullException.ThrowIfNull(genericType);
var result = new List<Type>();
AddImplementedGenericTypes(result, givenType, genericType);
return result;
}
/// <summary>
/// 尝试获取类成员及其声明类型上定义的单个特性,包括继承的特性
/// 如果未找到则返回默认值
/// </summary>
/// <typeparam name="TAttribute">特性类型</typeparam>
/// <param name="memberInfo">成员信息</param>
/// <param name="defaultValue">默认值(默认为 null</param>
/// <param name="inherit">是否从基类继承特性</param>
/// <returns>找到的特性实例或默认值</returns>
public static TAttribute? GetSingleAttributeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute? defaultValue = default, bool inherit = true)
where TAttribute : Attribute
{
ArgumentNullException.ThrowIfNull(memberInfo);
// 使用 GetCustomAttributes 方法获取特性
return memberInfo.IsDefined(typeof(TAttribute), inherit)
? memberInfo.GetCustomAttributes(typeof(TAttribute), inherit).Cast<TAttribute>().First()
: defaultValue;
}
/// <summary>
/// 尝试获取类成员或其声明类型上定义的单个特性,包括继承的特性
/// 如果未找到则返回默认值
/// </summary>
/// <typeparam name="TAttribute">特性类型</typeparam>
/// <param name="memberInfo">成员信息</param>
/// <param name="defaultValue">默认值(默认为 null</param>
/// <param name="inherit">是否从基类继承特性</param>
/// <returns>找到的特性实例或默认值</returns>
public static TAttribute? GetSingleAttributeOfMemberOrDeclaringTypeOrDefault<TAttribute>(MemberInfo memberInfo, TAttribute? defaultValue = default, bool inherit = true)
where TAttribute : class
{
ArgumentNullException.ThrowIfNull(memberInfo);
return memberInfo.GetCustomAttributes(inherit).OfType<TAttribute>().FirstOrDefault()
?? SysReflection.GetTypeInfo(memberInfo.DeclaringType).GetCustomAttributes(inherit).OfType<TAttribute>().FirstOrDefault()
?? defaultValue;
}
/// <summary>
/// 获取类成员及其声明类型上定义的所有特性,包括继承的特性
/// </summary>
/// <typeparam name="TAttribute">特性类型</typeparam>
/// <param name="memberInfo">成员信息</param>
/// <param name="inherit">是否从基类继承特性</param>
/// <returns>特性集合</returns>
public static IEnumerable<TAttribute> GetAttributesOfMemberOrDeclaringType<TAttribute>(MemberInfo memberInfo, bool inherit = true)
where TAttribute : class
{
ArgumentNullException.ThrowIfNull(memberInfo);
var customAttributes = memberInfo.GetCustomAttributes(inherit).OfType<TAttribute>();
var declaringTypeCustomAttributes =
SysReflection.GetTypeInfo(memberInfo.DeclaringType).GetCustomAttributes(inherit).OfType<TAttribute>();
return declaringTypeCustomAttributes != null
? customAttributes.Concat(declaringTypeCustomAttributes).Distinct()
: customAttributes;
}
/// <summary>
/// 通过完整属性路径从给定对象获取属性值
/// </summary>
/// <param name="obj">目标对象</param>
/// <param name="objectType">对象类型</param>
/// <param name="propertyPath">属性路径(支持嵌套属性,用点分隔)</param>
/// <returns>属性值,如果属性不存在则返回 null</returns>
public static object? GetValueByPath(object obj, Type objectType, string propertyPath)
{
ArgumentNullException.ThrowIfNull(obj);
ArgumentNullException.ThrowIfNull(objectType);
ArgumentException.ThrowIfNullOrWhiteSpace(propertyPath);
var value = obj;
var currentType = objectType;
var objectPath = currentType.FullName;
var absolutePropertyPath = propertyPath;
if (objectPath != null && absolutePropertyPath.StartsWith(objectPath))
{
absolutePropertyPath = absolutePropertyPath.Replace(objectPath + ".", "");
}
foreach (var propertyName in absolutePropertyPath.Split('.'))
{
var property = currentType.GetProperty(propertyName);
if (property != null)
{
if (value != null)
{
value = property.GetValue(value, null);
}
currentType = property.PropertyType;
}
else
{
value = null;
break;
}
}
return value;
}
/// <summary>
/// 递归获取指定类型中的所有公共常量值(包括基类型)
/// </summary>
/// <param name="type">目标类型</param>
/// <returns>常量值数组</returns>
public static string[] GetPublicConstantsRecursively(Type type)
{
ArgumentNullException.ThrowIfNull(type);
const int MaxRecursiveParameterValidationDepth = 8;
var publicConstants = new List<string>();
static void Recursively(List<string> constants, Type targetType, int currentDepth)
{
if (currentDepth > MaxRecursiveParameterValidationDepth)
{
return;
}
constants.AddRange(targetType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(x => x.IsLiteral && !x.IsInitOnly)
.Select(x => x.GetValue(null)!.ToString()!));
var nestedTypes = targetType.GetNestedTypes(BindingFlags.Public);
foreach (var nestedType in nestedTypes)
{
Recursively(constants, nestedType, currentDepth + 1);
}
}
Recursively(publicConstants, type, 1);
return [.. publicConstants];
}
/// <summary>
/// 通过完整属性路径设置给定对象的属性值
/// </summary>
/// <param name="obj">目标对象</param>
/// <param name="objectType">对象类型</param>
/// <param name="propertyPath">属性路径(支持嵌套属性,用点分隔)</param>
/// <param name="value">要设置的值</param>
internal static void SetValueByPath(object obj, Type objectType, string propertyPath, object value)
{
ArgumentNullException.ThrowIfNull(obj);
ArgumentNullException.ThrowIfNull(objectType);
ArgumentException.ThrowIfNullOrWhiteSpace(propertyPath);
var currentType = objectType;
PropertyInfo property;
var objectPath = currentType.FullName!;
var absolutePropertyPath = propertyPath;
if (absolutePropertyPath.StartsWith(objectPath))
{
absolutePropertyPath = absolutePropertyPath.Replace(objectPath + ".", "");
}
var properties = absolutePropertyPath.Split('.');
if (properties.Length == 1)
{
property = objectType.GetProperty(properties.First())!;
property.SetValue(obj, value);
return;
}
for (var i = 0; i < properties.Length - 1; i++)
{
property = currentType.GetProperty(properties[i])!;
obj = property.GetValue(obj, null)!;
currentType = property.PropertyType;
}
property = currentType.GetProperty(properties.Last())!;
property.SetValue(obj, value);
}
/// <summary>
/// 添加实现的泛型类型到结果列表
/// </summary>
/// <param name="result">结果列表</param>
/// <param name="givenType">给定类型</param>
/// <param name="genericType">泛型类型</param>
private static void AddImplementedGenericTypes(List<Type> result, Type givenType, Type genericType)
{
var givenTypeInfo = SysReflection.GetTypeInfo(givenType);
if (givenTypeInfo.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
{
result.AddIfNotContains(givenType);
}
foreach (var interfaceType in givenTypeInfo.GetInterfaces())
{
if (SysReflection.GetTypeInfo(interfaceType).IsGenericType && interfaceType.GetGenericTypeDefinition() == genericType)
{
result.AddIfNotContains(interfaceType);
}
}
if (givenTypeInfo.BaseType == null)
{
return;
}
AddImplementedGenericTypes(result, givenTypeInfo.BaseType, genericType);
}
#endregion
#region
/// <summary>
/// 获取包含有某特性的类
/// 第一种实现
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
public static IEnumerable<Type> GetContainsAttributeTypes<TAttribute>()
where TAttribute : Attribute
{
return GetAllTypes()
.Where(e => e.CustomAttributes.Any(g => g.AttributeType == typeof(TAttribute)));
}
/// <summary>
/// 获取包含有某特性的类
/// 第二种实现
/// </summary>
/// <param name="attribute"></param>
/// <returns></returns>
public static IEnumerable<Type> GetContainsAttributeTypes(Attribute attribute)
{
return GetAllTypes()
.Where(e => e.CustomAttributes.Any(g => g.AttributeType == attribute.GetType()));
}
#endregion
#region
/// <summary>
/// 获取不包含有某特性的类
/// 第一种实现
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
public static IEnumerable<Type> GetFilterAttributeTypes<TAttribute>()
where TAttribute : Attribute
{
return GetAllTypes()
.Where(e => e.CustomAttributes.All(g => g.AttributeType != typeof(TAttribute)));
}
/// <summary>
/// 获取包含有某特性的类
/// 第二种实现
/// </summary>
/// <param name="attribute"></param>
/// <returns></returns>
public static IEnumerable<Type> GetFilterAttributeTypes(Attribute attribute)
{
return GetAllTypes()
.Where(e => e.CustomAttributes.All(g => g.AttributeType != attribute.GetType()));
}
#endregion
#region ()
/// <summary>
/// 获取某类的子类(非抽象类)
/// 第一种实现
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static IEnumerable<Type> GetSubClasses<T>()
where T : class
{
return GetAllTypes()
.Where(t => t is { IsInterface: false, IsClass: true, IsAbstract: false })
.Where(t => typeof(T).IsAssignableFrom(t));
}
/// <summary>
/// 获取某类的子类(非抽象类)
/// 第二种实现
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<Type> GetSubClasses(Type type)
{
return GetAllTypes()
.Where(t => t is { IsInterface: false, IsClass: true, IsAbstract: false })
.Where(type.IsAssignableFrom);
}
/// <summary>
/// 获取某泛型接口的子类(非抽象类)
/// </summary>
/// <param name="interfaceType"></param>
/// <returns></returns>
public static IEnumerable<Type> GetSubClassesByGenericInterface(Type interfaceType)
{
return [.. GetAllTypes()
.Where(type => type is { IsInterface: false, IsClass: true, IsAbstract: false }
&& type.GetInterfaces().Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == interfaceType))];
}
#endregion ()
#region ()
/// <summary>
/// 获取继承自某类的包含有某特性的接口、类的子类(非抽象类)
/// 第一种实现
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
public static IEnumerable<Type> GetContainsAttributeSubClasses<T, TAttribute>()
where T : class
where TAttribute : Attribute
{
return GetSubClasses<T>().Intersect(GetContainsAttributeTypes<TAttribute>());
}
/// <summary>
/// 获取继承自某类的包含有某特性的接口、类的子类(非抽象类)
/// 第二种实现
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<Type> GetContainsAttributeSubClasses<TAttribute>(Type type)
where TAttribute : Attribute
{
return GetSubClasses(type).Intersect(GetContainsAttributeTypes<TAttribute>());
}
#endregion ()
#region ()
/// <summary>
/// 获取继承自某类的不包含有某特性的接口、类的子类(非抽象类)
/// 第一种实现
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TAttribute"></typeparam>
/// <returns></returns>
public static IEnumerable<Type> GetFilterAttributeSubClass<T, TAttribute>()
where T : class
where TAttribute : Attribute
{
return GetSubClasses<T>().Intersect(GetFilterAttributeTypes<TAttribute>());
}
/// <summary>
/// 获取继承自某类的不包含有某特性的接口、类的子类(非抽象类)
/// 第二种实现
/// </summary>
/// <typeparam name="TAttribute"></typeparam>
/// <param name="type"></param>
/// <returns></returns>
public static IEnumerable<Type> GetFilterAttributeSubClass<TAttribute>(Type type)
where TAttribute : Attribute
{
return GetSubClasses(type).Intersect(GetFilterAttributeTypes<TAttribute>());
}
#endregion ()
#region
/// <summary>
/// 获取当前应用程序的 NuGet 程序包依赖项
/// </summary>
/// <param name="prefix">前缀名</param>
/// <returns>NuGet 包信息列表</returns>
public static List<NuGetPackage> GetNuGetPackages(string prefix)
{
var nugetPackages = new Dictionary<string, NuGetPackage>();
// 获取当前应用所有程序集
var assemblies = GetEffectivePatchAssemblies(prefix, "dll");
// 查找被引用程序集中的 NuGet 库依赖项
foreach (var assembly in assemblies)
{
try
{
var referencedAssemblies = assembly.GetReferencedAssemblies()
.Where(s => !s.FullName.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase) &&
!s.FullName.StartsWith("System", StringComparison.OrdinalIgnoreCase))
.Where(s => !string.IsNullOrEmpty(s.Name) && s.Version != null);
foreach (var referencedAssembly in referencedAssemblies)
{
// 检查引用的程序集是否来自 NuGet
if (string.IsNullOrEmpty(referencedAssembly.Name) || referencedAssembly.Version == null)
{
continue;
}
var packageName = referencedAssembly.Name;
var packageVersion = referencedAssembly.Version.ToString();
// 避免重复添加相同的 NuGet 包,保留版本更高的
if (!nugetPackages.TryGetValue(packageName, out var value))
{
nugetPackages[packageName] = new NuGetPackage
{
PackageName = packageName,
PackageVersion = packageVersion
};
}
else
{
var existingVersion = Version.Parse(value.PackageVersion);
var currentVersion = referencedAssembly.Version;
if (currentVersion > existingVersion)
{
nugetPackages[packageName] = new NuGetPackage
{
PackageName = packageName,
PackageVersion = packageVersion
};
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine($"Error processing assembly {assembly.FullName}: {ex.Message}");
}
}
return [.. nugetPackages.Values.OrderBy(p => p.PackageName)];
}
#endregion
#region
/// <summary>
/// 判断程序集是否为系统程序集(如微软官方程序集)
/// </summary>
/// <param name="assembly">要检查的程序集</param>
/// <returns>如果是系统程序集则返回 true否则返回 false</returns>
private static bool IsSystemAssembly(Assembly assembly)
{
ArgumentNullException.ThrowIfNull(assembly);
var asmCompanyAttr = assembly.GetCustomAttribute<AssemblyCompanyAttribute>();
if (asmCompanyAttr is null)
{
return false;
}
var companyName = asmCompanyAttr.Company;
return companyName.Contains("Microsoft", StringComparison.OrdinalIgnoreCase);
}
/// <summary>
/// 通过程序集路径判断是否为系统程序集
/// </summary>
/// <param name="assemblyPath">程序集文件路径</param>
/// <returns>如果是系统程序集则返回 true否则返回 false</returns>
private static bool IsSystemAssembly(string assemblyPath)
{
ArgumentException.ThrowIfNullOrWhiteSpace(assemblyPath);
try
{
var assembly = Assembly.LoadFrom(assemblyPath);
return IsSystemAssembly(assembly);
}
catch
{
return false;
}
}
/// <summary>
/// 判断程序集是否有效(能否正常加载类型)
/// </summary>
/// <param name="assembly">要验证的程序集</param>
/// <returns>如果程序集有效则返回 true否则返回 false</returns>
private static bool IsValid(Assembly assembly)
{
ArgumentNullException.ThrowIfNull(assembly);
try
{
_ = assembly.GetTypes();
_ = assembly.DefinedTypes.ToList();
return true;
}
catch (ReflectionTypeLoadException)
{
return false;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 判断指定文件是否为托管程序集
/// </summary>
/// <param name="file">程序集文件路径</param>
/// <returns>如果是托管程序集则返回 true否则返回 false</returns>
private static bool IsManagedAssembly(string file)
{
ArgumentException.ThrowIfNullOrWhiteSpace(file);
try
{
using var fs = File.OpenRead(file);
using PEReader peReader = new(fs);
return peReader.HasMetadata && peReader.GetMetadataReader().IsAssembly;
}
catch
{
return false;
}
}
/// <summary>
/// 安全地尝试加载程序集,处理各种加载异常
/// </summary>
/// <param name="assemblyPath">程序集文件路径</param>
/// <returns>成功加载的程序集,失败则返回 null</returns>
private static Assembly? TryLoadAssembly(string assemblyPath)
{
ArgumentException.ThrowIfNullOrWhiteSpace(assemblyPath);
if (!File.Exists(assemblyPath))
{
return null;
}
Assembly? assembly = null;
try
{
var assemblyName = AssemblyName.GetAssemblyName(assemblyPath);
assembly = Assembly.Load(assemblyName);
}
catch (BadImageFormatException ex)
{
Debug.WriteLine($"BadImageFormatException loading assembly {assemblyPath}: {ex.Message}");
}
catch (FileLoadException ex)
{
Debug.WriteLine($"FileLoadException loading assembly {assemblyPath}: {ex.Message}");
}
catch (Exception ex)
{
Debug.WriteLine($"Exception loading assembly {assemblyPath}: {ex.Message}");
}
if (assembly is not null)
{
return assembly;
}
try
{
assembly = Assembly.LoadFile(assemblyPath);
}
catch (BadImageFormatException ex)
{
Debug.WriteLine($"BadImageFormatException loading file {assemblyPath}: {ex.Message}");
}
catch (FileLoadException ex)
{
Debug.WriteLine($"FileLoadException loading file {assemblyPath}: {ex.Message}");
}
catch (Exception ex)
{
Debug.WriteLine($"Exception loading file {assemblyPath}: {ex.Message}");
}
return assembly;
}
#endregion
}
/// <summary>
/// 程序集相等性比较器
/// 用于比较两个程序集是否相等,基于程序集名称进行匹配
/// </summary>
internal class AssemblyEquality : EqualityComparer<Assembly>
{
/// <summary>
/// 比较两个程序集是否相等
/// </summary>
/// <param name="x">第一个程序集</param>
/// <param name="y">第二个程序集</param>
/// <returns>如果两个程序集相等则返回 true否则返回 false</returns>
public override bool Equals(Assembly? x, Assembly? y)
{
return (x is null && y is null) ||
(x is not null && y is not null &&
AssemblyName.ReferenceMatchesDefinition(x.GetName(), y.GetName()));
}
/// <summary>
/// 获取程序集的哈希代码
/// </summary>
/// <param name="obj">程序集对象</param>
/// <returns>程序集的哈希代码</returns>
/// <exception cref="ArgumentNullException">当程序集为 null 时</exception>
public override int GetHashCode(Assembly obj)
{
ArgumentNullException.ThrowIfNull(obj);
return obj.GetName().FullName.GetHashCode(StringComparison.OrdinalIgnoreCase);
}
}
/// <summary>
/// NuGet 程序包信息记录
/// 表示一个 NuGet 包的基本信息,包括包名和版本
/// </summary>
public record NuGetPackage
{
/// <summary>
/// NuGet 包名称
/// </summary>
public string PackageName { get; init; } = string.Empty;
/// <summary>
/// NuGet 包版本号
/// </summary>
public string PackageVersion { get; init; } = string.Empty;
/// <summary>
/// 获取包的完整标识符
/// </summary>
/// <returns>格式为 "PackageName@PackageVersion" 的字符串</returns>
public override string ToString()
{
return $"{PackageName}@{PackageVersion}";
}
}