我正在使用WPF和Prism开发模块化应用程序
我的所有 UserControls 都有单独的程序集并实现 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)},
...
};
我可以从上面写的列表中获得所有想要的UserControls(userControlTypes) 这背后的原因是什么?
供参考:
答案 0 :(得分:1)
此行为是设计使然。除非调用/输入强制它加载,否则.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
。这会产生更少的开销。
答案 1 :(得分:1)
AppDomain.GetAssemblies()
告诉您加载的程序集,而不是引用的程序集。我无法谈论你的问题的棱镜方面,我同意这些评论,可能有更好的方法来设计它。但...
如果你真的想枚举可能加载到AppDomain
中的所有类型,你可以通过枚举现有程序集中的类型(即你已经在这里完成,使用AppDomain.CurrentDomain.GetAssemblies()
,然后为每个程序集调用GetReferencedAssemblies()
),它返回一组AssemblyName
值,您可以使用它们来加载其他程序集。对于其中的每一个,您可以依次检查所有类型(以查找IUserControl
的实现者)并调用GetReferencedAssemblies()
以继续递归搜索。
请注意,此仍然不一定会返回您的进程可能加载的IUserControl
接口的所有实现者。程序集可以通过除AppDomain
程序集中引用之外的方式加载,例如通过代码搜索目录中的候选项,甚至是用户明确命名要加载的程序集。这就是为什么使用您正在使用的任何API直接支持的机制是一种更好的方法,以确保您找到该API可以找到的那些程序集。