私はいくつかのC#クラスライブラリを作成し、Ninjectを使用してクラスに依存性注入を提供したいと考えています。クラスライブラリがロードされる各ファイルで実行されるコード(メソッド)をクラスライブラリが宣言することは可能ですか?Ninjectのバインディングを定義するためにこれが必要です。
5 に答える
C++のDllMainに相当するものを探しているようです。C#でこれを行う方法はありません。
シナリオについて、およびDllMainスタイルの関数で実行するためにコードが必要な理由についてもう少し詳しく教えてください。
型に静的コンストラクターを定義しても、この問題は解決しません。静的型コンストラクターは、型自体が何らかの方法で使用される前にのみ実行されることが保証されています。静的コンストラクターを定義し、タイプにアクセスしないDLL内の他のコードを使用すると、そのコンストラクターは実行されません。
AppDomain.AssemblyLoad
イベントに参加しましたか?アセンブリがロードされた後に起動します。
AppDomain.CurrentDomain.AssemblyLoad += (s, e) =>
{
Assembly justLoaded = e.LoadedAssembly;
// ... etc.
};
私は過去9か月間、Ninjectをかなり使用してきました。バインディングを登録するために、librayに存在するモジュールをNinjectカーネルに「ロード」する必要があるように思えます。
Ninject1.xと2.0ベータのどちらを使用しているかわかりません。2つのバージョンは、概念的には同じですが、動作が少し異なります。この議論では、バージョン1.xを使用します。私が知らないもう1つの情報は、メインプログラムがNinjectカーネルをインスタンス化していて、ライブラリがそのカーネルにバインディングを追加しているだけなのか、ライブラリ自体にカーネルとバインディングが含まれているのかということです。ライブラリ内のバインディングを、メインアセンブリ内の既存のNinjectカーネルに追加する必要があると想定しています。最後に、このライブラリを動的にロードしていて、メインプログラムに静的にリンクされていないことを前提としています。
最初に行うことは、すべてのバインディングを登録するライブラリ内のninjectモジュールを定義することです。これはすでに行っている可能性がありますが、言及する価値があります。例えば:
public class MyLibraryModule : StandardModule {
public override void Load() {
Bind<IMyService>()
.To<ServiceImpl>();
// ... more bindings ...
}
}
バインディングがNinjectモジュール内に含まれているので、アセンブリをロードするときにそれらを簡単に登録できます。アセンブリをロードすると、StandardModuleから派生したすべてのタイプをスキャンできるという考え方です。これらのタイプを取得したら、それらをカーネルにロードできます。
// Somewhere, you define the kernel...
var kernel = new StandardKernel();
// ... then elsewhere, load your library and load the modules in it ...
var myLib = Assembly.Load("MyLibrary");
var stdModuleTypes = myLib
.GetExportedTypes()
.Where(t => typeof(StandardModule).IsAssignableFrom(t));
foreach (Type type in stdModuleTypes) {
kernel.Load((StandardModule)Activator.CreateInstance(type));
}
注意すべき点の1つは、上記のコードをさらに一般化して、複数のライブラリをロードし、複数のタイプを登録できることです。また、前述したように、Ninject 2にはこの種の機能が組み込まれています。実際には、ディレクトリをスキャンし、アセンブリをロードし、モジュールを登録する機能があります。とてもかっこいい。
シナリオが私が概説したものとわずかに異なる場合は、同様の原則を適用できる可能性があります。
クライアントコードを制御できますか?はいの場合、アセンブリをロードするときに魔法をかける代わりに、バインディングを実行するRegistryのような単一のクラスを実装し、インターフェイスIRegistryを実装します。次に、ロード中に、アセンブリでIRegistryの実装を探し、必要なメソッドを実行できます。
クラスに属性を設定することもできます。
[Component(Implements=typeof(IMyDependency)]
これらの属性を探して、クライアント側のコンテナーにロードします。
または、このような状況のためのライブラリであるMEFを見ることができます。
私の知る限り、答えはノーです。私が理解しているように、クラスライブラリでIoCコンテナを構成する必要があります。その場合は、それを行うのは得策ではありません。クラスライブラリでバインディングを定義する場合は、次のようになります。依存性注入の使用?依存性注入を使用して、実行時に依存性を注入し、さまざまなシナリオでさまざまなオブジェクトを注入できます。ただし、IoCコンテナーを構成するのに最適な場所は、アプリケーションの起動です(IoCコンテナーはアプリケーションのバックボーンのようなものであるため) :))ただし、アプリケーションの起動を担当するブートストラップに配置する必要があります。単純なアプリケーションでは、Mainメソッドにすることができます。