使用yield return返回泛型T时程序冻结,求DLL继承类型获取方案
解决从DLL加载派生类型时程序冻结的问题
看起来你在从DLL提取继承自T的类型时遇到了程序卡顿/冻结的情况,我来帮你分析下问题所在,再给出修复方案。
首先说下你代码里的几个关键问题:
- 类型转换逻辑错误:你把
Type对象强转成T的实例((T)(Object)type)——这完全不对!如果你的目标是获取继承自T的类型列表,方法返回值应该是IEnumerable<Type>;如果是要创建T的实例,那得用Activator.CreateInstance来实例化类型,而不是直接转换Type对象。 - 未处理类型加载异常:
Assembly.GetTypes()会触发所有类型的静态构造函数,还会尝试加载依赖类型,如果某个类型依赖缺失或者加载失败,很可能导致程序卡住甚至崩溃,而且你没有任何异常捕获逻辑。 - 加载方式可能导致依赖阻塞:
Assembly.LoadFrom会自动尝试解析依赖,但如果依赖DLL找不到,它可能会在系统路径里反复查找,这会造成长时间的卡顿。
修复后的代码(获取派生类型列表)
如果你的需求是获取所有继承自T的类型,用这个版本:
using System.IO; using System.Reflection; using System.Collections.Generic; static IEnumerable<Type> GetAllDerivedTypes<T>(string dllPath) { // 先检查文件是否存在,避免无效加载 if (!File.Exists(dllPath)) throw new FileNotFoundException("指定的DLL文件不存在", dllPath); // 可选:如果不需要创建实例,用ReflectionOnlyLoadFrom可以避免加载到应用域,减少资源占用 // Assembly assembly = Assembly.ReflectionOnlyLoadFrom(dllPath); Assembly assembly = Assembly.LoadFrom(dllPath); if (assembly == null) yield break; Type baseType = typeof(T); // 优先获取公共导出类型,减少不必要的加载 foreach (Type type in assembly.GetExportedTypes()) { try { // 过滤:是类、非抽象、继承自T if (type.IsClass && !type.IsAbstract && type.IsSubclassOf(baseType)) { Console.WriteLine(type.Name); yield return type; } } catch (TypeLoadException ex) { // 捕获加载失败的类型,记录日志或提示,避免整个流程卡住 Console.WriteLine($"无法加载类型 {type.Name}: {ex.Message}"); } } }
如果需要创建T的实例列表
如果你的目标是生成T的实例,用这个版本(注意要确保T有可访问的默认构造函数):
static IEnumerable<T> CreateAllDerivedInstances<T>(string dllPath) where T : class { if (!File.Exists(dllPath)) throw new FileNotFoundException("指定的DLL文件不存在", dllPath); Assembly assembly = Assembly.LoadFrom(dllPath); if (assembly == null) yield break; Type baseType = typeof(T); foreach (Type type in assembly.GetExportedTypes()) { try { if (type.IsClass && !type.IsAbstract && type.IsSubclassOf(baseType)) { Console.WriteLine(type.Name); // 创建实例,这里假设类型有默认构造函数 T instance = Activator.CreateInstance(type) as T; if (instance != null) yield return instance; } } catch (Exception ex) { Console.WriteLine($"创建{type.Name}实例失败: {ex.Message}"); } } }
额外避免冻结的建议
- 异步执行:如果是UI程序,把这个加载逻辑放到
Task里执行,比如用await Task.Run(() => GetAllDerivedTypes<T>(dllPath)),避免阻塞UI线程。 - 处理依赖问题:确保目标DLL的所有依赖文件都在可访问路径(比如和当前程序同目录),或者注册
AppDomain.CurrentDomain.AssemblyResolve事件来手动加载依赖。 - 减少不必要的加载:用
GetExportedTypes()代替GetTypes(),只处理公共类型,能大幅减少加载压力。
内容的提问来源于stack exchange,提问作者Jianhui Wang
相关产品推荐
相关产品推荐

