You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用yield return返回泛型T时程序冻结,求DLL继承类型获取方案

解决从DLL加载派生类型时程序冻结的问题

看起来你在从DLL提取继承自T的类型时遇到了程序卡顿/冻结的情况,我来帮你分析下问题所在,再给出修复方案。

首先说下你代码里的几个关键问题:

  1. 类型转换逻辑错误:你把Type对象强转成T的实例((T)(Object)type)——这完全不对!如果你的目标是获取继承自T的类型列表,方法返回值应该是IEnumerable<Type>;如果是要创建T的实例,那得用Activator.CreateInstance来实例化类型,而不是直接转换Type对象。
  2. 未处理类型加载异常:Assembly.GetTypes()会触发所有类型的静态构造函数,还会尝试加载依赖类型,如果某个类型依赖缺失或者加载失败,很可能导致程序卡住甚至崩溃,而且你没有任何异常捕获逻辑。
  3. 加载方式可能导致依赖阻塞: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 07:36:50