我所拥有的是一个“驱动程序”,它从某些来源重复收集数据.这些是我的插件.每个插件都需要初始化.现在我有一个接口,这些插件需要实现.
interface IDriverLiveCollection { ILiveCollection GetCollection(ILog logger,IDriverConfig config); }
该接口基本上是从插件创建ILiveCollection的实例.为了更好地理解ILiveCollection看起来像这样.
interface ILiveCollection { void GetData(Parameter param,DataWriter writer); void ShutDown(); }
还有初始化循环:
foreach(IDriverConfig config in DriverConfigs) { //Use MEF to load correct driver var collector = this.DriverLoader(config.DriverId).GetCollection(new Logger,config); // someTimer is an IObservable<Parameter> that triggers to tell when to collect data. someTimer.Subscribe((param)=> collector.GetData(param,new DataWriter(param))); }
问题是某些驱动程序可能需要比其配置更多的信息才能进行初始化.例如,某些驱动程序需要在初始化期间为它们提供一组参数.
我可以轻松地将界面扩展到现在看起来像:
interface IDriverLiveCollection { ILiveCollection GetCollection(ILog logger,IDriverConfig config,IEnumerable<Parameter> params); }
这种方法的缺点是公共接口已经改变,现在我需要重新编译每个驱动程序,即使之前没有任何需要此参数列表才能运行.我打算有大量的驱动程序,我也无法控制谁编写驱动程序.
我想到了另一个解决方案.我可以创建接口,在我调用Get Collection之间和我订阅定时器之间的循环中,我可以检查ILiveCollection对象是否也扩展了其中一个接口:
interface InitWithParameters { void InitParams(IEnumerable<Parameter> params); }
在我的循环中:
foreach(IDriverConfig config in DriverConfigs) { //Use MEF to load correct driver var collector = this.DriverLoader(config.DriverId).GetCollection(new Logger,config); // Check to see if this thing cares about params. if(collector is InitWithParameters) { ((InitWithparameters)collector).InitParams(listofParams); } // Continue with newly added interfaces. // someTimer is an IObservable<Parameter> that triggers to tell when to collect data. someTimer.Subscribe((param)=> collector.GetData(param,new DataWriter(param))); }
这里的不同之处在于我不需要重新编译每个驱动程序以使其工作.旧驱动程序将不是InitWithParameters类型,并且不会以这种方式调用,而新驱动程序将能够利用新接口.如果旧驱动程序想要利用它,那么它可以简单地实现该接口并重新编译.底线:除非他们想要功能,否则我不需要重新编译驱动程序.
我已经认识到的缺点是:我显然需要重新编译哪个程序在这个循环中.当新驱动程序与旧版本的程序一起使用时,会出现版本控制问题,这可能会导致某些问题.最后,随着这些事情的发展,我必须在循环中保存一个包含程序中每种可能类型的巨大列表.
编辑附加信息:
我试图在IDriverLiveCollection上使用MEF,而不是在ILiveCollection上,因为IDriverLiveCollection允许我使用自定义初始化参数构造特定的ILiveCollection.
可以有2个相同类型的ILiveCollections(2个FooLiveCollections),每个ILiveCollections具有不同的ILog和IDriverConfig,并且可能具有IEnumerable.我希望能够在“初始化循环”期间指定这些,而不是在插件组成时.
解决方法
[ImportingConstructor]
属性处理整个基础结构.
这允许您的插件准确指定它们需要能够构造的内容,而不必在以后提供和构造类型.
实际上,您的主机应用程序只需要:
// This gets all plugins [ImportMany] IEnumerable<ILiveCollection> LiveCollections { get; set; }
然后每个插件都有它们导出它的类型,即:
[Export(typeof(ILiveCollection))] public class FooLiveCollection : ILiveCollection { [ImportingConstructor] public FooLiveCollection(ILog logger,IDriverConfig config) { // ...
或者,插件可以省略一个构造函数参数,或添加laters(不影响以前的插件),即:
[ImportingConstructor] public BarLiveCollection(ILog logger,IBarSpecificValue barParam) { // ...
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。