9

プラグイン管理要件を解決するためにMEFを使用することを考えています。宣伝文句では「ハードな依存関係はありません」と書かれていますが、私が見る限り、インポート/エクスポートインターフェイスにはハードな依存関係があります。

私の懸念はこれです。私の拡張可能なアプリは私が書いたものです。プラグインはサードパーティによって作成されています。それで、私たち全員がV1から始めたとしましょう。私のアプリはIPlugin、プラグインの「パーツ」が実装する必要のあるインターフェースを定義しています。アプリをデプロイし、ユーザーが多数のサードパーティプラグインをインストールします。すべてうまくいっています。

次に、アプリをアップグレードし、プラグインインターフェイスに新しいメソッドを追加したいと思います。私の見方には2つの選択肢があります。

  1. インターフェイスを編集します-おそらく悪いです、そしてこれはそれらがもはやインターフェイスを正しく実装しないので既存のプラグインを壊します。
  2. 元のインターフェイスを継承する新しい「V2」インターフェイスを作成します

    パブリックインターフェイスIPluginV2:IPlugin {}

今、私は問題を抱えています。私のユーザーは全員、多数のサードパーティプラグインを実装IPluginしていますが、IPluginV2を実装する必要があります。開発者が新しいインターフェースを実装するまで、これらのサードパーティのプラグインは機能しなくなると思います。

MEFにはこの状況に対処する方法がありますか?古いプラグインを再構築せずに引き続き機能させながら、アプリを進化させる方法を本当に探しています。それを処理する最良の方法は何ですか?

4

2 に答える 2

15

バージョニングの場合、各バージョンのインターフェースとアダプターパターンがそれらの間を行き来することをお勧めします。これは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ます。固定の説明を返し、Inithost引数には何もしませんが、 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プラグインとして扱うことができます。IPluginIPluginV2

ホストのインターフェイスでアダプタパターンを使用して、V2プラグインがV1ホストで動作できるようにすることもできます。

もう1つのアプローチは、MEFと統合でき、アダプターを使用したバージョン管理をサポートできるautofacIoCです。

于 2013-02-25T19:54:02.367 に答える
1

ソリューションのブレインストーミングに役立つ可能性のあるいくつかの提案(私はテストしていません):

  1. MEFを使用する場合AggregateCatalogは、バージョンごとに異なるものを使用してください。そうすれば、V1プラグインとV2プラグインの両方を利用できるように維持できます

  2. MEFを使用していない場合、サードパーティからダイナミックロードされたDLLは、実装されている現在のインターフェイスバージョンを返す必要があり、バージョン番号に応じて発信できる呼び出しを選択できます。

それは役に立ちましたか?

乾杯、ディマムラ

于 2013-02-25T10:04:40.633 に答える