c# - 如何在AppDomain中找到尚未加载的类型?

标签 c# .net wpf reflection prism

我正在使用 WPF 和 Prism 开发模块化应用程序。
我的所有 UserControls 都有单独的程序集并实现 IUserControl 接口(interface)。
我想以这种方式列出所有实现 IUserControl 接口(interface)的类型,形成加载的模块库;

//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 的所有类时,如下所示;

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

我可以从上面写的列表中获取所有所需的用户控件(userControlTypes)。
这背后的原因是什么?

仅供引用:

  • 所有程序集都针对相同的 .NET 框架版本。
  • 我的 Prism 版本是 6.1.0
  • 我将使用 userControlTypes 向最终用户显示应用程序内的所有 UserControl 类型。
  • IUserControl界面不包含任何内容。

最佳答案

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

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

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

所以如果你想要AppDomain.CurrentDomain.GetAssemblies要在应用程序中加载所有类型,您需要强制程序集加载到内存中(如果尚未这样做)。根据您的结构,您可以通过几种方法来完成此操作。

  1. 迭代磁盘上的 .dll 文件(使用类似 Assembly.GetExecutingAssembly.Location 的引用位置)并调用 Assembly.LoadFrom 。使用通配符确保您只加载程序集,而不是您遇到的每个 .dll 库。
  2. 在配置文件中引用感兴趣的类型并从那里加载它们。您可以使用Type t = Type.GetType(yourConfigType);从配置字符串列表创建类型列表时。
  3. 在配置文件中引用感兴趣的程序集,并以与选项 1 相同的方式加载到 DLL 中。
  4. 只需像在上一个示例中那样对列表进行硬编码即可。

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

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

关于c# - 如何在AppDomain中找到尚未加载的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35418131/

相关文章:

c# - 使用 HwndHost 在 WPF 中托管外部窗口的正确方法

c# - 这个带有 "yield"的函数如何详细工作?

c# - Entity Framework 中的一个事务中的多个数据库

c# - 如何从此函数将当前年龄检索到文本框?

c# - 如何在 Unity Android 应用程序中使用 OAuth 2.0 获取访问 token ?

c# - C#中的图像和几何

c# - 如何将 ViewData 传递给类中的 Action 方法?

c# - 当选择选项卡时,如何更改 TabControl 的 TabItem 标题上的图像?

.NET 3.5 SP1 作为要求(或者我应该尝试 3.5 w/o SP1)?

WPF用户控件: can I bind properties from an internal and an external datacontext?