27

私はDIを学んでいて、最近最初のプロジェクトを作成しました。

このプロジェクトでは、リポジトリパターンを実装しました。私はインターフェースと具体的な実装を持っています。私のプログラムが動的にロードする「プラグイン」、dllとして私のインターフェースの実装を構築することは可能かどうか疑問に思います。

したがって、プログラムを再構築しなくても、時間の経過とともにプログラムを改善できます。dllを「プラグイン」フォルダに配置し、設定を変更して、ボイラーを作成するだけです。

これは可能ですか?Ninjectはこれを支援できますか?

4

9 に答える 9

26

Sean Chambers のソリューションは、プラグインを制御する場合には機能しますが、プラグインがサード パーティによって開発された可能性があり、ninject モジュールの作成に依存する必要がない場合には機能しません。

これは、NinjectのConventions Extensionを使用すると非常に簡単に実行できます。

public static IKernel CreateKernel()
{
    var kernel = new StandardKernel();

    kernel.Scan(scanner => {
        scanner.FromAssembliesInPath(@"Path\To\Plugins");
        scanner.AutoLoadModules();
        scanner.WhereTypeInheritsFrom<IPlugin>();
        scanner.BindWith<PluginBindingGenerator<IPlugin>>();
    });

    return kernel;
}

private class PluginBindingGenerator<TPluginInterface> : IBindingGenerator
{
    private readonly Type pluginInterfaceType = typeof (TPluginInterface);

    public void Process(Type type, Func<IContext, object> scopeCallback, IKernel kernel)
    {
        if(!pluginInterfaceType.IsAssignableFrom(type))
            return;
        if (type.IsAbstract || type.IsInterface)
            return;
        kernel.Bind(pluginInterfaceType).To(type);
    }
}

その後、ロードされたすべてのプラグインをkernel.GetAll<IPlugin>().

この方法の利点は次のとおりです。

  1. プラグイン dll は、ninject でロードされていることを知る必要はありません
  2. 具体的なプラグイン インスタンスは ninject によって解決されるため、プラグイン ホストが構築方法を知っている型を注入するためのコンストラクターを持つことができます。
于 2011-12-12T23:08:26.083 に答える
12

この質問は、私がここで提供したのと同じ回答に適用されます: NInject はオンデマンドでモジュール/アセンブリをロードできますか?

これがあなたが探しているものだと確信しています:

var kernel = new StandardKernel();
kernel.Load( Assembly.Load("yourpath_to_assembly.dll");

Ninject.dll のリフレクターを使用して KernelBase を見ると、この呼び出しによって、読み込まれたアセンブリ内のすべてのモジュールが再帰的に読み込まれることがわかります (Load メソッドは IEnumerable を受け取ります)。

public void Load(IEnumerable<Assembly> assemblies)
{
    foreach (Assembly assembly in assemblies)
    {
        this.Load(assembly.GetNinjectModules());
    }
}

私はこれを、非常に頻繁に変更されるものへの直接のアセンブリ参照を望まず、アプリケーションに別のモデルを提供するためにアセンブリを交換できるシナリオで使用しています (適切なテストが実施されていることを前提としています)。

于 2009-11-14T05:27:57.903 に答える
11

v.2に基づく@ungood良い回答を拡張すると、Ninjectのv.3(現在はRC3)でさらに簡単になります。IPluginGenerator はもう必要ありません。次のように記述してください。

var kernel = new StandardKernel();
kernel.Bind(scanner => scanner.FromAssembliesInPath(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location))
                                   .SelectAllClasses()
                                   .InheritedFrom<IPlugin>()
                                   .BindToAllInterfaces());

アプリケーションの同じパスに IPlugin を実装するプラグイン (ここにインターフェイスを配置) を探していることに注意してください。

于 2012-03-15T12:42:39.383 に答える
3

通常のC#リフレクションで簡単に実行でき、追加のテクノロジは必要ありません。

Webにはかなりの数の例があります。たとえば、 http: //www.codeproject.com/KB/cs/c__plugin_architecture.aspx

一般に、メインアプリケーションでは、プラグインを実装するアセンブリをロードする必要があります。例:

ass = Assembly.Load(name);

次に、プラグインのインスタンスを作成する必要があります。クラスの名前を知っている場合は、次のようになります。

ObjType = ass.GetType(typename);
IPlugin plugin = (IPlugin)Activator.CreateInstance(ObjType);

そして、あなたはそれを使うだけです。

于 2008-12-01T14:02:09.853 に答える
1

Managed Extensibility Framework をご覧ください。http://www.codeplex.com/MEF

于 2009-11-05T17:00:20.753 に答える
0

これを実行するには複数の方法があり、事前定義されたインターフェイスを介して具体的な実装を行うことで、これを達成するための主な目標をすでに達成しています。現実的には、インターフェイスが安定していれば、コアアプリケーションから構築できるはずです。

ただし、実装がNinjectでどのように機能するかはわかりません。これは、プロバイダーモデルまたはリフレクションを使用して行うことができます。リフレクションはやり過ぎだと思いますが、絶対に行う必要がない場合は。

プロバイダーモデルのアプローチでは、ファイルを/ binフォルダー、またはプローブしている他のフォルダーに配置し、プロバイダーの存在を反映するように.configファイルを調整します。特定の「プラグイン」フォルダーがある場合は、アプリケーションの起動時に呼び出されるメソッドを作成できます。それ以外の場合は、新しいインスタンスまたは削除されたインスタンスをスキャンしてプロバイダーをリロードします。

これは、ASP.NETのC#またはVBで機能します。ただし、他のアプリケーションを実行している場合は、別のアプローチを検討する必要があります。プロバイダーは、実際には、戦略パターンに関するMicrosoftのスピンにすぎません。

于 2008-12-01T14:05:16.617 に答える
0

私はこれをActivator.CreateInstance+Ninjectのヒットとして取得し、この領域で何かを指摘したかっただけです。うまくいけば、SOに関するこの質問に対する本当のキラーな答えを思い付くように誰かを刺激するでしょう。

モジュールとクラスを自動スキャンしてNinjectに適切に登録する問題がまだ発生しておらず、Activator.CreateInstanceを介してプラグインを作成している場合は、CreateInstanceを使用して依存関係を注入できます。

IKernel k = ...
var o = Activator.CreateInstance(...);
k.Inject( o );

もちろん、これはhttp://groups.google.com/group/ninject/browse_thread/thread/880ae2d14660b33cのようなものに向かう途中の一時的な解決策にすぎません。

于 2009-01-28T15:26:11.000 に答える
0

フレームワークは必要ないと思います。このチュートリアルはあなたの問題を解決しますhttp://www.codeproject.com/KB/cs/c__plugin_architecture.aspx

于 2011-11-29T02:24:32.373 に答える
-1

問題は、モジュールのロードでセットアップしたオブジェクトがプログラム内で使用されている場合、再コンパイルが必要になる可能性があることです。その理由は、プログラムにクラスのアセンブリの最新バージョンがない可能性があるためです。たとえば、インターフェイスの1つに新しい具象クラスを作成する場合、プラグインdllを変更するとします。これで、Injectorはそれを正常にロードしますが、プログラム内に返される場合(kernel.get(...))、プログラムにアセンブリがない可能性があり、エラーがスローされます。

私が話していることの例:

BaseAuto auto = kernel.Get<BaseAuto>();//Get from the NInjector kernel your object. You get your concrete objet and the object "auto" will be filled up (interface inside him) with the kernel.

//Somewhere else:

public class BaseModule : StandardModule
{
        public override void Load(){
            Bind<BaseAuto>().ToSelf();
            Bind<IEngine>().To<FourCylinder>();//Bind the interface
        }     
 }

SixCylinderと呼ばれる新しいFourCylinderを作成した場合、実際のプログラムには新しいオブジェクトへの参照がありません。したがって、PlugInからBaseModule.csをロードすると、参照で問題が発生する可能性があります。これを実行できるようにするには、この具象実装の新しいdllをプラグインとともに配布する必要があります。プラグインには、InjectorがInterfacetoConcreteクラスをロードするために必要なモジュールが含まれます。これは問題なく実行できますが、プラグインからのロード時にアプリケーション全体が存在するようになり、いくつかの点で問題が発生する可能性があります。注意してください。

ただし、プラグイン情報が必要な場合は、CodeProjectからチュートリアルを入手できます。

于 2008-12-01T14:03:35.030 に答える