Ninject(または他の容器)を使用して、どのようにしてサービスを要求しているタイプを見つけることができますか?
-
23-08-2019 - |
質問
私はサービスのためのインタフェースを持っていると仮定します:
public interface IFooService
{
void DoSomething();
}
そして、一般的なものであり、そのサービスの具体的な実装ます:
public class FooService<TRequestingClass> : IFooService
{
public virtual void DoSomething() { }
}
私はIFooServiceのインスタンスを必要とする他のいくつかのクラスがあります:
public class Bar
{
private IFooService _fooService;
public Bar(IFooService fooService)
{
this._fooService = fooService;
}
}
私はバーが作成されるとき、それはFooService <バー>のコンストラクタ引数を渡されるように私のIoCコンテナを配線する必要があります。ちょうどバーのような他の多くのクラスがあります。 TRequestingClassがIFooServiceのインスタンスを必要とするクラスの型である場合にはそれぞれ、また、それらに渡さFooService
FooService
public class FooService : IFooService
{
public FooService(string requestingClassName) { }
}
の私はこの方法で、依存関係を構築するために私のIoCコンテナを配線することができますどのように?の
あなたが混乱している場合は、私はなぜこのような奇妙な構造をしたいあなたはlog4net.LogManager.GetLogger(typeof演算(工ass))で作成されますのILogを取得するときにlog4netのが最善の方法について考えます。私はごみにlog4netのへの参照と私のコードをしたくないので、私はシンプルなILoggerですインタフェースを記述しており、このようなもので、それを実装したいと思います:
public class GenericLogger<T> : ILogger
{
private readonly ILog log;
public GenericLogger()
{
this.log = log4net.LogManager.GetLogger(typeof(T));
}
public void Debug(object message)
{
this.log.Debug(message);
}
/* .... etc .... */
}
解決
最も簡単な方法は、ILogger<T>
インターフェイスを作成するには、次のようになります。
public class ILogger<T> : ILogger { }
public class GenericLogger<T> : ILogger<T> { ... }
次に、正しい型を取得するために、一般的な型推論に依存しています。例えば、Ninjectで、以下のバインディングはあなたが必要とするだろう、すべてのです。
Bind(typeof(ILogger<>)).To(typeof(GenericLogger<>));
次に、あなたがかかるタイプは次のようになります:
public class FooService : IFooService {
public FooService(ILogger<FooService> logger) { ... }
}
あなたはILogger<T>
インターフェイスに対して断固なら、あなたは親の型を決定するためにIContext
を読み取ってカスタムプロバイダ、のような、より創造的な何かを行うことができます。
public class GenericLogger : ILogger {
public class GenericLogger(Type type) { ... }
}
public class LoggerProvider : Provider<ILogger> {
public override ILogger CreateInstance(IContext context) {
return new GenericLogger(context.Target.Member.ReflectedType);
}
}
そして、かかる種類は次のように動作します
public class FooService : IFooService {
public FooService(ILogger logger) { ... }
}
他のヒント
、なぜ単にあなたGericLoggerコンストラクタは、オブジェクトの型であるパラメータを取ることはありませ。そして、次の操作を行います。
ILog = kernel.Get<ILog>(ParameterList);
私はNinjectのパラメータリストの上に完全にまだアップ読んでいないが、IParameterListを使用して、パラメータの種類を注入する方法であるように思われる。
EDITます:
これは次のように動作しますようにになります。
ILog = kernel.Get<ILog>(new ConstructorArgument[] {
new ConstructorArgument("ClassName", this.GetType().Name)
})
そして、あなたが持っているあなたのILog
class GenericLogger : Ilog
{
GenericLogger(string ClassName) {};
}
私は(私は最近Ninject2ツリーで探しています)Ninjectソースからのようですまさに、これをテストしませんでした。
EDITます:
あなたはConstructorArgument、ないパラメータを渡したいです。反映するために更新されました。
このコードを印刷します:
"初期から呼び出されました"class Init {
public void Run() {
StandardKernel kernel = new StandardKernel( new MyLoader() );
kernel.Get<Tester>( new ConstructorArgument[] {
new ConstructorArgument( "ClassName",
this.GetType().Name
)
} );
}
}
public class Tester {
public Tester(string ClassName) {
Console.WriteLine("Called From {0}", ClassName);
}
}
EDITます:
は有用かもしれない別の方法は、バインド()を使用することである。自己結合または.WhenInjectedInto()条件付きのいずれかで使用される場合、有用であり得る()。WithConstructorArgument()結合することができる。
カスタムプロバイダのアイデアについて詳しく説明するために、ここでそれを行うための簡単な方法があります...
internal class LogModule : StandardModule
{
private class log4netILogProvider : SimpleProvider<log4net.ILog>
{
protected override ILog CreateInstance(IContext context)
{
return LogManager.GetLogger(context.Instance.GetType());
}
}
public override void Load()
{
Bind<log4net.ILog>().ToProvider(new log4netILogProvider());
}
}
次に、注入されたクラスでます:
[Inject]
public ILog logger { get; set; }