我正在尝试使用 MEF2 创建一个简单的插件系统。
在我的场景中,我将只有 1-10 个插件,因此我决定不费心在单独的域中加载程序集以避免性能问题;无论如何这会很好,但它似乎对导出的对象造成了一些限制(必须是[Serializable]
并派生自MarshalByRefObject
:参见https://msdn.microsoft.com/en-us/library/ms972968.aspx和http://www .codeproject.com/Articles/1091726/The-Nuances-of-Loading-and-Unloading-Assemblies-wi和https://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();