Ninject(または他の容器)を使用して、どのようにしてサービスを要求しているタイプを見つけることができますか?

StackOverflow https://stackoverflow.com/questions/719346

質問

私はサービスのためのインタフェースを持っていると仮定します:

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 のインスタンスが必要になる場合があります。私はIFooServiceの消費者にこのquirkinessを公開する必要はありません。彼らは気にする必要があり、すべてのは、彼らが渡されたIFooServiceのメソッドを呼び出すことができるということです。彼らは、彼らが渡されたIFooServiceの具体的な実装を構築するために特別な何かを必要とすることを知っている必要はありません。

FooService に受け入れalternatativeは、それがために作成されているクラスの名前が含まれているそのconstructurでの文字列引数を持つ非ジェネリッククラスであるだろう。すなわちます:

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; }    
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top