【问题标题】:Assembly.GetTypes() - ReflectionTypeLoadExceptionAssembly.GetTypes() - ReflectionTypeLoadException
【发布时间】:2011-02-09 03:20:10
【问题描述】:

我们为我们的应用程序实现了一个插件框架,并使用 Assembly.Loadfrom 加载插件程序集。然后我们使用 GetTypes() 并进一步检查每个插件文件的类型以获取支持的接口。

插件的路径由用户提供,我们循环浏览文件夹中的每个文件以查看它(插件)是否支持我们的插件接口。如果是,我们创建一个实例,如果不是,我们移动到下一个文件。

我们从一个代码库(appA_1 和 appA_2)构建两个版本的软件。

当插件由与插件文件同时构建的应用程序加载时,加载插件效果很好。但是,如果我们构建 appA_2 并指向 appA_1 的插件文件夹,则在调用 GetTypes() 时会出现异常。

我们的代码的基本版本是;

var pluginAssembly = Assembly.LoadFrom(FileName);    
foreach (var pluginType in pluginAssembly.GetTypes())
{

我们得到一个“ReflectionTypeLoadException”异常。

这是令人担忧的,因为我们希望我们的应用程序能够加载由任何人构建的任何插件的类型。我们缺少什么吗?

编辑: 在遍历 LoaderExceptions 之后,我们发现有一个文件 libPublic.dll 会生成 System.IO.FileNotFoundException 异常。奇怪的是,这个文件驻留在应用程序目录中,而插件被引用到项目文件中。

编辑 2: 在异常日志中,我们发现以下内容 “比较程序集名称导致不匹配:修订号”

【问题讨论】:

  • 异常信息是什么?异常是否有内部异常?那是什么信息?
  • 您不使用现有框架(如 MEF)的任何原因?
  • 在使用 MEF 时仍然会产生类似的问题,尽管 MEF 绝对可以方便地处理繁琐的工作。
  • 谢谢你。你的智慧令人印象深刻!
  • 您使用的是强名称程序集吗?默认情况下,绑定到这些是特定于版本的。

标签: c# reflection plugins assemblies


【解决方案1】:

一些事情:

  • 确保插件目录中没有重复的程序集(即,您已经从应用程序目录加载到主应用程序的程序集。)否则,当您加载插件时,它可能会加载额外的同一个组件。这可能会导致一些有趣的异常,例如:

    对象(“MyObject”类型)不是“MyObject”类型。

  • 如果在实例化类型时遇到异常,可能需要处理AppDomain.AssemblyResolve

    private void App_Startup(object sender, StartupEventArgs e)
    {
        // Since we'll be dynamically loading assemblies at runtime, 
        // we need to add an appropriate resolution path
        // Otherwise weird things like failing to instantiate TypeConverters will happen
        AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;
    }
    
    private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        var domain = (AppDomain) sender;
    
        foreach (var assembly in domain.GetAssemblies())
        {
            if (assembly.FullName == args.Name)
            {
                return assembly;
            }
        }
    
        return null;
    }
    

我意识到必须告诉 CLR,为了解析程序集,找到具有我们用于解析的名称的程序集,这有点奇怪,但我看到没有它会发生奇怪的事情。例如,我可以从插件程序集中实例化类型,但如果我尝试使用TypeDescriptor.GetConverter,它不会找到该类的TypeConverter,即使它可以看到该类的Converter 属性。


查看您的编辑,这可能不是导致当前异常的原因,尽管您稍后在使用插件时可能会遇到这些问题。

【讨论】:

  • 你太棒了!我有重复的装配问题,所以这个答案救了我!
  • 这也解决了我的问题。我正在加载我的插件,它公开了一个自定义 UITypeEditor 和 TypeConverters,虽然我的类型会加载,但编辑器/转换器不会实例化。此外,我的插件位于相对于应用程序的子目录中,奇怪的是,如果我将插件放在与主机应用程序相同的目录中,它就可以正常工作。该解决方案有助于使插件在任何位置都能正常工作。
  • 你是绝对正确的。我也在父应用程序中已经存在的子应用程序中加载程序集。当我加载 AppDomain.CurrentDomain.GetAssemblies() 时,我得到了程序集并解决了 GetTypes() 中的加载程序问题。非常感谢 :) @Dan Dryant
  • 绝对救星...这解决了我从动态加载的程序集中遇到的所有缺失类型的巫术。一百万年后,我永远不会期望解决方案是this
【解决方案2】:

您遇到的程序集版本不匹配。由于您的插件引用了此libPublic.dll,因此您必须仔细对其进行版本控制,特别是不要影响其修订/构建/等。每次编译时的数字。

【讨论】:

    【解决方案3】:

    感谢这篇文章,我可以解决我在UITypeEditor 中遇到的ReflectionTypeLoadException。它是自定义类库的设计器程序集(在设计时使用的 winforms 智能标签),用于扫描某些类型。

    /// <summary>
    /// Get the types defined in the RootComponent.
    /// </summary>
    private List<Type> getAssemblyTypes(IServiceProvider provider)
    {
        var types = new List<Type>();
        try
        {
            IDesignerHost host = (IDesignerHost)provider.GetService(typeof(IDesignerHost));
            ITypeResolutionService resolution = (ITypeResolutionService)provider.GetService(typeof(ITypeResolutionService));
            AppDomain.CurrentDomain.AssemblyResolve += (sender, args) =>
            {
                foreach (var assembly in ((AppDomain)sender).GetAssemblies())
                {
                    if (assembly.FullName == args.Name)
                    {
                        return assembly;
                    }
                }
    
                return null;
            };
    
            Type rootComponentType = resolution.GetType(host.RootComponentClassName, false);
            types = rootComponentType.Assembly.GetTypes().ToList();
        }
        catch
        {
        }
    
        return types;
    }
    

    【讨论】:

    猜你喜欢
    • 2011-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-01
    • 2018-10-21
    相关资源
    最近更新 更多