1

我正在尝试使用 MEF2 创建一个简单的插件系统。

在我的场景中,我将只有 1-10 个插件,因此我决定不费心在单独的域中加载程序集以避免性能问题;无论如何这会很好,但它似乎对导出的对象造成了一些限制(必须是[Serializable]并派生自MarshalByRefObject:参见https://msdn.microsoft.com/en-us/library/ms972968.aspxhttp://www .codeproject.com/Articles/1091726/The-Nuances-of-Loading-and-Unloading-Assemblies-wihttps://msdn.microsoft.com/en-us/magazine/jj133818.aspx),我需要它们成为 POCO 对象,因为我无法控制它们的来源。

我只需要加载从特定接口派生的所有导出类型的程序集,因此我创建了一个简单的目录类,它扫描目录以收集程序集,并可以返回一个配置了约定的 MEF2 容器,导出从 T 派生的所有类型(请参阅以下)。

无论如何,当我尝试使用它时,即使正确找到并加载了容器程序集,我也无法在目录中进行任何导出。当然,我在 MEF2 导出约定中遗漏了一些东西,有人能指出我的解决方案吗?

您可以在这里找到完整的虚拟复制解决方案https://onedrive.live.com/redir?resid=F8DEF93587EC2C1!258076&authkey=!AKSKUhMwFhV0n-k&ithint=file%2czip

以下是相关代码和使用示例:

public sealed class PluginCatalog<T>
{
    private readonly string _sFileMask;
    private readonly List<Assembly> _aAssemblies;
    private bool _bLoaded;

    public string SourceDirectory { get; }

    public bool IsRecursive { get; }

    public PluginCatalog(string directory, string fileMask = "*.dll", bool recursive = false)
    {
        _aAssemblies = new List<Assembly>();
        _sFileMask = fileMask;
        SourceDirectory = directory;
        IsRecursive = recursive;
    }

    private void LoadPluginAssemblies(string directory)
    {
        if (directory == null) throw new ArgumentNullException(nameof(directory));

        // scan DLLs
        foreach (string sFilePath in Directory.GetFiles(directory, _sFileMask))
        {
            Assembly asm = Assembly.LoadFrom(sFilePath);
            if (asm.GetTypes().Any(typeof(T).IsAssignableFrom)) _aAssemblies.Add(asm);
        }

        // scan subdirectories if required
        if (IsRecursive)
        {
            foreach (string sSubdir in Directory.GetDirectories(directory))
                LoadPluginAssemblies(sSubdir);
        }

        _bLoaded = true;
    }

    public CompositionHost GetContainer()
    {
        if (!_bLoaded) LoadPluginAssemblies(SourceDirectory);

        // export all the types implementing the requested interface type
        ConventionBuilder builder = new ConventionBuilder();
        builder.ForTypesMatching(t => typeof(T).IsAssignableFrom(t)).Export<T>();

        // create the container from all the plugins assemblies
        return new ContainerConfiguration()
            .WithAssemblies(_aAssemblies)
            .CreateContainer();
    }
}

使用示例:

PluginCatalog<IAnimal> catalog = new PluginCatalog<IAnimal>(directoryName, "*Plugin*.dll");
CompositionHost container = catalog.GetContainer();
var animals = container.GetExports<IAnimal>().ToList();
4

0 回答 0