C# 如何在AppDomain中查找尚未加载的类型?
我正在使用WPF和Prism开发模块化应用程序。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
所有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
在应用程序中加载所有类型,则需要强制程序集加载到内存中(如果尚未加载)。根据你的结构,你可以用几种方法来做
Assembly.getExecutionGassembly.location
)并调用。使用通配符确保只加载程序集,而不是加载遇到的每个.dll库Type t=Type.GetType(yourConfigType)代码>从配置字符串列表创建类型列表时
还要注意,一旦将程序集加载到应用程序域中,就不能在该应用程序域的生命周期内卸载它。如果您不希望这样做,但仍然希望动态查找所有类型,则必须创建第二个应用程序域来查找所有类型,并将它们作为数组/完全限定类型名列表作为字符串返回。然后可以卸载此创建的应用程序域。此外,正如@Peter在下面的评论中正确地指出的那样,如果您采用这种方法,请使用
reflectiononnlyloadfrom
。这会产生更少的开销。AppDomain.GetAssemblies()
告诉您加载的程序集,而不是引用的程序集。我不能谈论你问题的棱镜方面,我同意你的评论,即可能有更好的设计方法。但是
如果确实要枚举可能加载到AppDomain
中的所有类型,可以通过枚举现有程序集中的类型(即,正如您在这里所做的那样,使用AppDomain.CurrentDomain.GetAssemblies()
,但对于每个程序集,调用getReferenceAssemblys()
)来近似此操作,它返回可用于加载其他程序集的AssemblyName
值数组。对于每种类型,您可以依次检查它们的所有类型(以查找IUserControl
的实现者),并调用getReferenceAssembly()
继续递归搜索
请注意,这仍然不一定返回进程可能加载的
IUserControl
接口的所有实现者。除了在AppDomain
的程序集中引用程序集之外,还可以通过其他方式加载程序集,例如通过代码搜索候选目录,甚至用户显式命名要加载的程序集。这就是为什么使用由您正在使用的任何API直接支持的机制是一种更好的方法,以确保您准确地找到该API将找到的程序集。可能您应该使用您的容器来执行此操作,这就是它的用途。让模块注册它的实现类型,然后解析接口。我同意你的看法。我可以这样做<代码>容器.注册表类型(userControlTypes,WithMappings.None,WithName.Default,WithLifetime.Transient)代码>但我想知道你能做到吗