[英]How to find a type that is not loaded yet in AppDomain?
我正在使用WPF和Prism开发模块化应用程序。
我所有的UserControl都有单独的程序集并实现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)},
...
};
我可以从上面我上面写的列表(userControlTypes)中获得所有需要的UserControls。
这背后的原因是什么?
仅供参考:
此行为是设计使然。 .net CLR不会在程序集中加载,除非它被调用/输入强制将其加载。 想象一下,如果应用程序启动时目录中的每个.dll文件都被加载到内存中,而不是首次在运行时引用类型,则运行该应用程序的启动成本,某些具有大型库的应用程序的加载时间为分钟(甚至更多?)。 同样,这是不现实的,因为某些类型被解析为执行文件夹之外的库,例如解析为GAC的程序集。
在您的第一个示例AppDomain.CurrentDomain.GetAssemblies
它将仅返回该应用程序域中已加载的程序集,而不是所有程序集。 要查看此内容,您可以添加{typeof(ViziteUserControl)}
( 取自下一个代码部分 )并将其放置在其上方,这将强制CLR加载类型(和包含程序集),现在它( 包含组装 )也将返回AppDomain.CurrentDomain.GetAssemblies
。
在您的下一个代码片段中,您的代码将明确输入这些程序集并添加类型。 我认为这不需要任何解释。
因此,如果您希望AppDomain.CurrentDomain.GetAssemblies
跨应用程序加载所有类型,则需要强制将程序集加载到内存(如果尚未加载)。 根据您的结构,您可以通过两种方法执行此操作。
Assembly.GetExecutingAssembly.Location
),然后调用Assembly.LoadFrom 。 使用通配符可确保仅加载程序集,而不是遇到的每个.dll库。 Type t = Type.GetType(yourConfigType);
从配置字符串列表创建类型列表时。 如果选择选项1或3,则在调用Assembly.LoadFrom之前,必须检查以确保尚未将程序集加载到内存中。 您可以通过再次检查AppDomain.CurrentDomain.GetAssemblies().Any(x =>your search query)
加载的内容来执行此操作。
还要注意,一旦将程序集加载到应用程序域中,就无法在该应用程序域的生命期内卸载它。 如果您不希望这样做,但仍然想动态查找所有类型,则必须创建第二个应用程序域来查找所有类型,并将它们作为字符串/全限定类型名称的数组/列表返回。 然后,您可以卸载此创建的应用程序域。 另外,如下面的注释中@Peter所正确指出的那样,如果采用这种方法,请使用ReflectionOnlyLoadFrom
。 这样产生的开销要少得多。
AppDomain.GetAssemblies()
告诉您已加载的程序集,而不是所引用的程序集。 我无法谈及您问题的“棱镜”方面,我同意这样的意见,即可能有更好的设计方法。 但…
如果您真的想枚举可能在AppDomain
加载的所有类型,则可以通过枚举现有程序集中的类型来进行近似估算(即,如您在此处所做的那样,使用AppDomain.CurrentDomain.GetAssemblies()
,但是对于每个程序集,请调用GetReferencedAssemblies()
,它返回一个AssemblyName
值数组,可用于加载其他程序集。 对于每种类型,您可以依次检查它们的所有类型(以查找IUserControl
的实现者)并调用GetReferencedAssemblies()
继续进行递归搜索。
请注意,这仍然不一定会返回您的进程可能加载的IUserControl
接口的所有实现。 可以通过在AppDomain
的程序集中引用之外的其他方式来加载程序集,例如,通过代码在候选目录中搜索代码,甚至是用户明确命名要加载的程序集。 这就是为什么使用所使用的任何API直接支持的机制是一种更好的方法,以确保您准确找到该API将找到的那些程序集。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.