我的应用程序由几个核心程序集和几个扩展/插件程序集组成。为了让MEF知道插件必须提供的所有部件,我必须加载这些组件,即使我永远不会使用它们的任何部件。这使得应用程序需要更多时间来启动(如果我将在启动时加载所有程序集)并且还会增加内存占用。
理想情况下,在实际需要之前,我不必加载程序集。我只加载插件的导出数据,当我实际需要导入零件时,MEF会加载组件并提供零件。
我发现有些东西可以完成我刚写的所有内容,但在MEF CachedAssemblyCatalog - Lazy Loading of Assemblies中询问后,我发现这段代码不被认为是稳定的,并且不是由MEF团队维护的,所以我决定不使用它。
我的问题是如何才能实现这种行为:
对于需要提前解析插件以创建元数据程序集,XML文件或诸如此类的解决方案,我完全没问题。
答案 0 :(得分:2)
如果您刚刚延迟加载程序集,那么您可能会使用部分解决方案this question。您不需要获取该解决方案中检索到的所有信息。可能只有合同名称,装配名称以及零件是否正在导出或导入合同。然后,您可以编写一个目录,根据需要加载程序集,例如:
public sealed class DelayLoadingCatalog : ComposablePartCatalog
{
// List containing tuples which have the 'contract name'
// and the 'assembly name'
private readonly List<Tuple<string, string>> m_Plugins
= new List<Tuple<string, string>>();
private readonly Dictionary<string, AssemblyCatalog> m_Catalogs
= new Dictionary<string, AssemblyCatalog>();
public DelayLoadingCatalog(IEnumerable<Tuple<string, string>> plugins)
{
m_Plugins.AddRange(plugins);
}
public override IEnumerable<Tuple<ComposablePartDefinition, ExportDefinition>> GetExports(ImportDefinition definition)
{
var partsToLoad = m_Plugins
.Where(t => t.Item1.Equals(definition.ContractName));
foreach (var part in partsToLoad)
{
if (!m_Catalogs.ContainsKey(part.Item2.Name))
{
var assembly = Assembly.Load(new AssemblyName(part.Item2.Name));
m_Catalogs.Add(part.Item2.Name, new AssemblyCatalog(assembly));
}
}
return m_Catalogs.SelectMany(p => p.Value.GetExports(definition));
}
public override IQueryable<ComposablePartDefinition> Parts
{
get
{
throw new NotImplementedException();
}
}
}
然后可以像这样使用
class Program
{
public void Init()
{
var domainSetup = new AppDomainSetup
{
ApplicationBase = Directory.GetCurrentDirectory(),
};
var scanDomain = AppDomain.CreateDomain(
"scanDomain",
null,
domainSetup);
var scanner = scanDomain.CreateInstanceAndUnwrap(
typeof(MyScanner).Assembly.FullName,
typeof(MyScanner).FullName) as MyScanner;
var plugins = scanner.Scan(myPluginsPath);
// Make sure we don't have the assemblies loaded anymore ...
AppDomain.Unload(scanDomain);
var catalog = new DelayLoadingCatalog(plugins);
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
[Import("MyCoolExport")]
public object MyImport
{
get;
set;
}
}
示例DelayLoadCatalog不是很聪明,因为它会继续搜索元组列表。优化代码不应该太难。例如,您可以检查是否已加载所有程序集,并在该点停止搜索该列表。
答案 1 :(得分:0)
如果有人有兴趣,我自己实施了一个解决方案,最近在GitHub上提供了解决方案。 LazyAssemblyLoading解决方案允许用户序列化程序集的部件信息,然后使用它初始化LazyAssemblyCatalog
,只有在实际需要其中一个部件时才会加载程序集,同时仍然允许使用它没有加载程序集时像往常一样使用元数据。