我想用mef制作我的插件子系统,但是我没有什么问题,因为我是csharp和mef的新手(
我想做的是:
问题如下:
我的解决方案是好的吗?如果没有,我如何改进它(通过使用其他的东西)?
如何使用mef激活所有导出并调用指定的接口函数?
我将感谢所有的联系和批评。谢谢大家。
发布于 2011-09-12 17:47:30
基于@m的回答,我确实认为拥有一个公共界面是最好的设计。这是利用通用操作集的最简单方法,您可以将这些操作应用到插件中。不过,我要考虑的是,略为完善一下:
public interface IPlugin : IDisposable
{
void Initialise();
}通过强制实现Dispose方法,您的部件可以由CompositionContainer的生存期管理特性自动控制。所有的卸载代码都可以放进去,下面是一个示例插件:
public interface ILogger : IPlugin
{
void Log(string message);
}
[Export(typeof(ILogger))]
public class ConsoleLogger : ILogger
{
void IPlugin.Initialise()
{
Console.WriteLine("Initialising plugin...");
}
public void Log(string message)
{
Console.WriteLine(message);
}
public virtual void Dispose(bool disposing)
{
if (disposing)
{
Console.WriteLine("Disposing plugin...");
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}Dispose模式允许用于清理代码的标准化机制。您的CompositionContainer实例将跟踪此项目,并在它被释放时清除它。
现在,我想描述的是MEFContrib中的一个很好的添加,叫做InterceptingCatalog。此目录允许您执行的是注册拦截策略,它允许您在将导出的值返回给调用代码之前访问它。其中一个用途可以是在第一次导出实例时自动确保在基本Initialise接口上调用IPlugin:
public class InitialisePluginStrategy : IExportedValueInterceptor
{
public object Intercept(object value)
{
var plugin = value as IPlugin;
if (plugin != null)
plugin.Initialise();
return value;
}
}让我们把这一切联系起来:
static void Main(string[] args)
{
var catalog = new AssemblyCatalog(typeof(Program).Assembly);
var configuration = new InterceptionConfiguration()
.AddInterceptor(new InitialisePluginStrategy());
var interceptingCatalog = new InterceptingCatalog(catalog, configuration);
var container = new CompositionContainer(interceptingCatalog);
var logger = container.GetExportedValue<ILogger>();
logger.Log("test");
Console.ReadKey();
}如果您运行它,您将注意到我们的ConsoleLogger是在我们第一次从容器中获得它时自动初始化的。我们不需要担心它再次被初始化,它只在创建导出实例时才会这样做,这意味着它遵从单例和非单例场景。
在这一点上,您可能会认为这可能会造成太大的损失,但实际上,这是一个非常优雅的解决方案,可以使您的部件自动启动,并在不再需要时进行处理。
当然,如果您想要对如何初始化您的部件进行细粒度的控制,您只需在您自己编写的方法中管理这些组件,那么您只需要考虑插件状态。
你可以在Piotr Włodek博客上读到更多关于Piotr Włodek博客的文章。
发布于 2011-09-12 13:21:40
如果您希望您的所有插件接口都坚持自己的接口,那么您应该为它们提供一个扩展的接口:
public interface IMyInterface
{
void Load();
void Unload();
}然后,当插件创建自己的接口时,它们应该从您公开提供的接口扩展:
public interface IPlugin1 : IMyInterface
{
void DoPlugin1Func();
}现在,为了获得在MEF中导出的接口集合,必须将接口标记为InheritedExport:
[InheritedExport(typeof(IMyInterface))]
public interface IMyInterface { ... }这说明任何从IMyInterface扩展的类都将作为一种IMyInterface类型导出,甚至在树下也是如此:
//This class will be exported as an IMyInterface
public class PluginImplementation1 : IPlugin1 { ... }最后,在代码中的某个地方(如果适用),您可以导入IMyInterface实例的集合。
public class SomeClass
{
[ImportMany(typeof(IMyInterface))]
private IEnumerable<IMyInterface> Plugins { get; set; }
}如果一切都连接正确,Plugins将是通过继承导出为IMyInterface的类的枚举。
资源:
https://stackoverflow.com/questions/7388115
复制相似问题