如何找到尚未在AppDomain中加载的类型? [英] How to find a type that is not loaded yet in AppDomain?

查看:161
本文介绍了如何找到尚未在AppDomain中加载的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用WPF和Prism开发模块化应用程序.
我所有的 UserControls 具有单独的程序集,并实现了 IUserControl 接口.
我想以这种方式列出所有实现IUserControl接口的Types形成一个加载的模块库;

I'm developing modular application using WPF and Prism.
All my UserControls have separate assemblies and implement IUserControl interface.
I would like to list all Types which implement IUserControl interface form a loaded module library in this way;

//ModuleA.cs
var interfaceType = typeof(IUserControl);
var userControlTypes = AppDomain.CurrentDomain.GetAssemblies()
            .SelectMany(s => s.GetTypes())
            .Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass);

但是我无法在 userControlTypes 列表中看到所有实现IUserControl的UserControl类型.
当我在Bootstrapper.cs中使用实现IUserControl的所有类时,如下所示;

But I cannot see all UserControl types implementing IUserControl in userControlTypes list.
When I use the all classes that implements IUserControl in Bootstrapper.cs like in the following;

var userControlTypes = new List<Type>()
{ 
      {typeof(HastaKayitControl)},
      {typeof(ViziteUserControl)},
      {typeof(DenemeUserControl)},
      ...
};

我可以从上面我上面写的列表(userControlTypes)中获得所有所需的UserControls.
这是什么原因造成的?

I can get all desired UserControls from the list just I wrote above(userControlTypes).
What is the reason behind this?

仅供参考:

  • 所有程序集都针对相同的.NET Framework版本.
  • 我的棱镜版本是6.1.0
  • 我将使用 userControlTypes 将应用程序内部的所有UserControl类型显示给最终用户.
  • IUserControl 界面不包含任何内容.
  • All assemblies target the same .NET framework version.
  • My Prism version is 6.1.0
  • I will use userControlTypes to show all UserControl types inside the application to the end-user.
  • IUserControl interface contains nothing.

推荐答案

此行为是设计使然..net CLR不会在程序集中加载,除非它被调用/输入强制将其加载.想象一下,如果应用程序启动时目录中的每个.dll文件都被加载到内存中,而不是第一次在运行时引用类型时,则运行该应用程序的启动成本,某些具有大型库的应用程序的加载时间为分钟(甚至更多?).同样,这是不现实的,因为某些类型被解析为执行文件夹之外的库,例如解析为GAC的程序集.

This behavior is by design. The .net CLR will not load in an assembly unless it is called/entered which forces it to be loaded. Imagine the startup cost of running an app if every .dll file in the directory were loaded into memory when the application started as opposed to when a type was referenced at run time for the first time, some apps with large libraries would have load times of minutes (maybe even more?). Also it would not be realistic because some types are resolved to libraries outside of the execution folder like assemblies that resolve to the GAC.

在第一个示例中, AppDomain.CurrentDomain.GetAssemblies 将仅返回该应用程序域中已加载的程序集,而不是所有程序集.要查看此内容,您可以添加 {typeof(ViziteUserControl)} (摘自下一个代码部分),并将其放在其上方,这将强制类型(并包含程序集)由CLR加载,现在它(包含程序集的类型)也将由 AppDomain.CurrentDomain.GetAssemblies 返回.

In your first example AppDomain.CurrentDomain.GetAssemblies will only return the loaded assemblies, not all the assemblies, in that application domain. To see this you could add a {typeof(ViziteUserControl)} (taken from your next code part) and place it right above it, this will force the type (and containing assembly) to be loaded by the CLR and now it (types containing assembly) too will be returned by AppDomain.CurrentDomain.GetAssemblies.

在您的下一个代码片段中,您的代码将明确输入这些程序集并添加类型.我认为这不需要任何解释.

In your next code fragment your code is explicitly entering these assemblies and adding the types. I do not think this requires any explaining.

因此,如果您希望 AppDomain.CurrentDomain.GetAssemblies 在整个应用程序中加载所有类型,则需要强制将程序集加载到内存(如果尚未加载).根据您的结构,您可以通过以下两种方法完成此操作.

So if you want AppDomain.CurrentDomain.GetAssemblies to load all your types across your application you need to force the assembly to load into memory if it has not already done so. Depending on your structure you could do this a couple of ways.

  1. 遍历磁盘上的.dll文件(使用参考位置,例如 Assembly.GetExecutingAssembly.Location ),然后调用
  1. Iterate through the .dll files on disk (using a reference location like Assembly.GetExecutingAssembly.Location) and call Assembly.LoadFrom. Use wild cards to ensure you are only loading your assemblies and not every .dll library you are encountering.
  2. Reference interested types in a configuration file and load them from there. You can use Type t = Type.GetType(yourConfigType); when creating your list of types from your configuration string list.
  3. Reference interested assemblies in a configuration file and load in the DLL in the same manner as option 1.
  4. Just hard code the list as you did in your last example.

如果选择选项1或3,则在调用Assembly.LoadFrom之前,必须检查以确保尚未将程序集加载到内存中.您可以通过再次检查 AppDomain.CurrentDomain.GetAssemblies().Any(x =>您的搜索查询)来执行此操作.

If you choose option 1 or 3 you will have to check to make sure you have not already loaded the assembly in memory before you call Assembly.LoadFrom. You can do this by again checking what is already loaded with AppDomain.CurrentDomain.GetAssemblies().Any(x =>your search query).

还请注意,一旦将程序集加载到您的应用程序域中,就无法在该应用程序域的生命期内卸载它.如果您不希望这样做,但仍想动态查找所有类型,则必须创建第二个应用程序域来查找所有类型,并将它们作为字符串/全限定类型名称的数组/列表返回.然后,您可以卸载此创建的应用程序域.此外,如下面的注释中正确地在@Peter 中指出的那样,如果使用这种方法,请使用 ReflectionOnlyLoadFrom .这样所产生的开销要少得多.

Also Note that once you load an assembly into your application domain you cannot unload it for the life of that application domain. If you do not want this but you still want to dynamically find all your types you will have to create a 2nd application domain to find all the types and return them as an array/list of fully qualified type name as a string. You can then unload this created application domain. Also, as correctly noted by @Peter below in the comments, use ReflectionOnlyLoadFrom if you go with this approach. This incurs much less overhead.

这篇关于如何找到尚未在AppDomain中加载的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆