バージョニングの場合、各バージョンのインターフェースとアダプターパターンがそれらの間を行き来することをお勧めします。これはSystem.AddIn
バージョン管理の処理方法であり、MEFでも機能します。
アプリケーションのV1に次のタイプがあるとします。
public interface IPlugin
{
string Name { get; }
string Publisher { get; }
string Version { get; }
void Init();
}
これは、 V1プラグイン対応アプリの唯一の契約です。アセンブリに含まれてい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
おり、ホストのアプリケーションベースパスの下の「plugins」フォルダに公開されます。
最後に、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.
}
これらは両方ともアセンブリに含まれてい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
host引数には何もしませんが、 V1コントラクトInit
からパラメーターなしを呼び出します。
そして最後に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
適応さ せて、検出されたすべてのプラグインの連結シーケンスを公開します。適応が完了すると、すべてのプラグインをV2プラグインとして扱うことができます。IPlugin
IPluginV2
ホストのインターフェイスでアダプタパターンを使用して、V2プラグインがV1ホストで動作できるようにすることもできます。
もう1つのアプローチは、MEFと統合でき、アダプターを使用したバージョン管理をサポートできるautofacIoCです。