对于版本控制,您可能希望每个版本都有一个接口,并在它们之间使用适配器模式。它是System.AddIn
处理版本控制的方式,它也适用于 MEF。
假设您的应用程序的V1有以下类型:
public interface IPlugin
{
string Name { get; }
string Publisher { get; }
string Version { get; }
void Init();
}
这是我们V1插件感知应用程序的唯一合同。它包含在 assembly 中Contracts.v1
。
然后我们有一个 V1插件:
[Export(typeof(IPlugin))]
public class SomePlugin : IPlugin
{
public string Name { get { return "Some Plugin"; } }
public string Publisher { get { return "Publisher A"; } }
public string Version { get { return "1.0.0.0"; } }
public void Init() { }
public override string ToString()
{
return string.Format("{0} v.{1} from {2}", Name, Version, Publisher);
}
}
导出为IPlugin
. 它包含在程序集中Plugin.v1
并发布在主机应用程序基本路径下的“插件”文件夹中。
最后是V1主机:
class Host : IDisposable
{
CompositionContainer _container;
[ImportMany(typeof(IPlugin))]
public IEnumerable<IPlugin> Plugins { get; private set; }
public Host()
{
var catalog = new DirectoryCatalog("plugins");
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
public void Dispose() { _container.Dispose(); }
}
它导入IPlugin
文件夹“插件”中的所有部件。
然后我们决定发布V2,因为我们想提供版本控制,所以我们需要无版本合约:
public interface IPluginV2
{
string Name { get; }
string Publisher { get; }
string Version { get; }
string Description { get; }
void Init(IHost host);
}
具有新属性和修改的方法签名。另外,我们为主机添加了一个接口:
public interface IHost
{
//Here we can add something useful for a plugin.
}
这两个都包含在 assembly 中Contracts.v2
。
为了允许版本控制,我们添加了一个从 V1 到 V2 的插件适配器:
class V1toV2PluginAdapter : IPluginV2
{
IPlugin _plugin;
public string Name { get { return _plugin.Name; } }
public string Publisher { get { return _plugin.Publisher; } }
public string Version { get { return _plugin.Version; } }
public string Description { get { return "No description"; } }
public V1toV2PluginAdapter(IPlugin plugin)
{
if (plugin == null) throw new ArgumentNullException("plugin");
_plugin = plugin;
}
public void Init(IHost host) { plugin.Init(); }
public override string ToString() { return _plugin.ToString(); }
}
这只是适应从IPlugin
到IPluginV2
。它返回一个固定的描述,并且Init
它对主机参数不做任何事情,但它Init
从V1合约中调用无参数。
最后是V2主机:
class HostV2WithVersioning : IHost, IDisposable
{
CompositionContainer _container;
[ImportMany(typeof(IPluginV2))]
IEnumerable<IPluginV2> _pluginsV2;
[ImportMany(typeof(IPlugin))]
IEnumerable<IPlugin> _pluginsV1;
public IEnumerable<IPluginV2> Plugins
{
get
{
return _pluginsV1.Select(p1 => new V1toV2PluginAdapter(p1)).Concat(_pluginsV2);
}
}
public HostV2WithVersioning()
{
var catalog = new DirectoryCatalog("plugins");
_container = new CompositionContainer(catalog);
_container.ComposeParts(this);
}
public void Dispose() { _container.Dispose(); }
}
它同时导入IPlugin
和IPluginV2
部分,将每个部分适应IPlugin
并IPluginV2
公开所有已发现插件的串联序列。适配完成后,所有插件都可以作为V2插件处理。
您还可以在主机接口上使用适配器模式,以允许V2插件与V1主机一起工作。
另一种方法是autofac IoC,它可以与 MEF集成并支持使用适配器进行版本控制。