Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/259.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在AppDomain中查找尚未加载的类型?_C#_.net_Wpf_Reflection_Prism - Fatal编程技术网

C# 如何在AppDomain中查找尚未加载的类型?

C# 如何在AppDomain中查找尚未加载的类型?,c#,.net,wpf,reflection,prism,C#,.net,Wpf,Reflection,Prism,我正在使用WPF和Prism开发模块化应用程序。 所有myUserControl都有单独的程序集,并实现IUserControl接口。 我想以这种方式列出实现IUserControl接口的所有类型,形成一个加载的模块库 //ModuleA.cs var interfaceType = typeof(IUserControl); var userControlTypes = AppDomain.CurrentDomain.GetAssemblies() .SelectMan

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

//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)},
      ...
};
var userControlTypes=new List()
{ 
{typeof(HastaKayitControl)},
{typeof(ViziteUserControl)},
{typeof(DenemeUserControl)},
...
};
我可以从上面写的列表(userControlTypes)中获得所有需要的UserControls 这背后的原因是什么

供参考:

  • 所有程序集都以相同的.NET framework版本为目标
  • 我的Prism版本是6.1.0
  • 我将使用userControlTypes向最终用户显示应用程序中的所有UserControl类型
  • IUserControl接口不包含任何内容

    • 这种行为是出于设计。.net CLR将不会加载到程序集中,除非调用/输入该程序集以强制加载它。想象一下,如果在应用程序启动时将目录中的每个.dll文件都加载到内存中,那么运行应用程序的启动成本会有多大。与第一次在运行时引用某个类型不同,一些具有大型库的应用程序的加载时间可能会长达几分钟(甚至更长?)。此外,这也不现实,因为某些类型解析为执行文件夹之外的库,就像解析为GAC的程序集一样

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

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

      因此,如果希望
      AppDomain.CurrentDomain.GetAssemblys
      在应用程序中加载所有类型,则需要强制程序集加载到内存中(如果尚未加载)。根据你的结构,你可以用几种方法来做

    • 遍历磁盘上的.dll文件(使用参考位置,如
      Assembly.getExecutionGassembly.location
      )并调用。使用通配符确保只加载程序集,而不是加载遇到的每个.dll库
    • 在配置文件中引用感兴趣的类型并从那里加载它们。您可以使用
      Type t=Type.GetType(yourConfigType)从配置字符串列表创建类型列表时
    • 在配置文件中引用感兴趣的程序集,并以与选项1相同的方式加载到DLL中
    • 只需像上一个示例中那样硬编码列表
    • 如果选择选项1或3,则在调用assembly.LoadFrom之前,必须检查以确保尚未在内存中加载程序集。您可以通过再次检查AppDomain.CurrentDomain.GetAssemblys().Any(x=>您的搜索查询)
      中已加载的内容来完成此操作


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

      AppDomain.GetAssemblies()
      告诉您加载的程序集,而不是引用的程序集。我不能谈论你问题的棱镜方面,我同意你的评论,即可能有更好的设计方法。但是

      如果确实要枚举可能加载到
      AppDomain
      中的所有类型,可以通过枚举现有程序集中的类型(即,正如您在这里所做的那样,使用
      AppDomain.CurrentDomain.GetAssemblies()
      ,但对于每个程序集,调用
      getReferenceAssemblys()
      )来近似此操作,它返回可用于加载其他程序集的
      AssemblyName
      值数组。对于每种类型,您可以依次检查它们的所有类型(以查找
      IUserControl
      的实现者),并调用
      getReferenceAssembly()
      继续递归搜索


      请注意,这仍然不一定返回进程可能加载的
      IUserControl
      接口的所有实现者。除了在
      AppDomain
      的程序集中引用程序集之外,还可以通过其他方式加载程序集,例如通过代码搜索候选目录,甚至用户显式命名要加载的程序集。这就是为什么使用由您正在使用的任何API直接支持的机制是一种更好的方法,以确保您准确地找到该API将找到的程序集。

      可能您应该使用您的容器来执行此操作,这就是它的用途。让模块注册它的实现类型,然后解析接口。我同意你的看法。我可以这样做<代码>容器.注册表类型(userControlTypes,WithMappings.None,WithName.Default,WithLifetime.Transient)但我想知道你能做到吗