サービスのインターフェースがあるとします。
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;
}
}
Bar が作成されたときに FooService<Bar> のコンストラクター引数が渡されるように、IoC コンテナーを接続する必要があります。Bar と同じように、他にも多くのクラスがあります。また、それぞれに FooService<TRequestingClass> のインスタンスを渡す必要がある場合もあります。ここで、TRequestingClass は、IFooService のインスタンスを必要とするクラスの型です。この奇抜さを IFooService の消費者に公開する必要はありません。彼らが気にする必要があるのは、渡された IFooService のメソッドを呼び出すことができるということだけです。渡された IFooService の具体的な実装を構築するために特別なものが必要であることを知る必要はありません。
FooService<T> の代わりとして受け入れられるのは、作成対象のクラスの名前を含む文字列引数をコンストラクターに持つ非ジェネリック クラスです。すなわち:
public class FooService : IFooService
{
public FooService(string requestingClassName) { }
}
このように IoC コンテナーを接続して依存関係を構築するにはどうすればよいですか?
なぜこのような奇妙な構造が必要なのか混乱している場合は、log4net.LogManager.GetLogger(typeof(SomeClass)) で作成された 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 .... */
}