延迟加载程序集/目录

Adi*_*ter 5 .net assemblies mef lazy-loading .net-4.5

我的应用程序由几个核心程序集和几个扩展/插件程序集组成.为了让MEF知道插件必须提供的所有部件,我必须加载这些组件,即使我永远不会使用它们的任何部件.这使得应用程序需要更多时间来启动(如果我将在启动时加载所有程序集)并且还会增加内存占用.

理想情况下,在实际需要之前,我不必加载程序集.我只加载插件的导出数据,当我实际需要导入零件时,MEF会加载组件并提供零件.

我发现有些内容几乎可以完成我刚写的所有内容,但在MEF CachedAssemblyCatalog - Lazy Loading of Assemblies中询问之后,我意识到这段代码不被认为是稳定的,并且不是由MEF团队维护的,所以我我决定不使用它.

我的问题是如何才能实现这种行为:

  • 能够访问插件程序集的导出元数据而无需加载其整个程序集.
  • 与导入零件的代码透明集成; 即像往常一样使用进口 - 其他人(专门的目录?)将在必要时负责装配组件并提供所要求的部件.
  • 不会丢失任何现有的MEF功能,例如重组,延迟类型等.

我完全没有一个解决方案,需要提前解析插件来创建元数据程序集,XML文件或诸如此类的东西.

Pet*_*rik 2

如果您刚刚延迟加载程序集,那么您可能会使用此问题的部分解决方案。您不需要获取该解决方案中检索到的所有信息。可能只有合同名称、装配名称以及零件是导出还是导入合同。然后,您可以编写一个目录来根据需要加载程序集,例如如下所示:

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(); 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样使用

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

DelayLoadCatalog 示例不是很智能,因为它会不断搜索元组列表。不过,优化代码应该不会太难。例如,您可以检查是否已加载所有程序集并在此时停止搜索该列表。