C#:过滤调用程序集的引用,排除包引用以查找特定类型
解决方案:过滤项目引用并查找特定类型
核心思路
要区分项目引用和NuGet包引用且不依赖程序集Name属性,可通过以下特征判定:
- 包引用的程序集通常携带
PackageId这类NuGet专属元数据 - 项目引用的程序集输出路径一般与主程序集(调用程序集)处于同一目录或解决方案关联目录
- 包引用的程序集大多来自系统级NuGet缓存目录
具体实现代码
using System; using System.Linq; using System.Reflection; public class AssemblyLocator { public static Type FindTargetTypeInProjectReferences(string targetTypeFullName) { // 获取调用方的程序集(即解决方案内的可执行程序集) Assembly callingAssembly = Assembly.GetCallingAssembly(); string mainAssemblyDir = System.IO.Path.GetDirectoryName(callingAssembly.Location); // 过滤引用,剔除所有包引用 var projectAssemblies = callingAssembly.GetReferencedAssemblies() .Select(asmName => { try { return Assembly.Load(asmName); } catch { // 加载失败的直接排除(多为未复制到输出目录的包引用) return null; } }) .Where(asm => asm != null) .Where(asm => { // 检查是否包含NuGet包元数据,有则判定为包引用 bool isPackageRef = asm.GetCustomAttributes<AssemblyMetadataAttribute>() .Any(attr => attr.Key == "PackageId"); // 检查是否来自NuGet缓存目录 bool isFromNuGetCache = asm.Location.Contains(@".nuget\packages\") || asm.Location.Contains(@"/.nuget/packages/"); // 检查是否和主程序集同目录(项目引用默认输出到此) bool isInMainOutputDir = System.IO.Path.GetDirectoryName(asm.Location) == mainAssemblyDir; // 保留规则:非包引用+非缓存目录,或者位于主输出目录的程序集 return !isPackageRef && !isFromNuGetCache || isInMainOutputDir; }); // 在筛选后的项目引用中查找目标类型 foreach (var asm in projectAssemblies) { try { Type foundType = asm.GetType(targetTypeFullName); if (foundType != null) { return foundType; } } catch { // 跳过加载类型失败的异常情况 continue; } } return null; } }
关键逻辑说明
- 加载引用程序集:通过
Assembly.Load加载引用项,加载失败的直接排除(包引用常未被复制到输出目录) - 目录匹配:项目引用的程序集默认会同步输出到主程序集目录,以此作为核心判断依据
- 元数据识别:利用NuGet包自动注入的
AssemblyMetadataAttribute标记,直接识别包引用 - 缓存目录排查:通过路径特征直接排除来自NuGet全局缓存的程序集
注意事项
- 若项目引用的程序集配置了自定义输出目录,需调整
mainAssemblyDir相关的判断逻辑,匹配自定义路径 - 对于强签名的程序集,也可通过公钥令牌区分,但需预先知晓项目引用的公钥信息,灵活性稍逊
内容的提问来源于stack exchange,提问作者Sarwan Surchi
相关产品推荐
相关产品推荐

