3

サービスのインターフェースがあるとします。

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 ....  */
}
4

3 に答える 3

6

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) { ... }
}
于 2009-04-05T18:19:00.137 に答える
1

私があなたを誤解していなければ、GericLogger Constructor にオブジェクトの型であるパラメーターを取らせないでください。次に、これを行います:

ILog = kernel.Get<ILog>(ParameterList);

Ninject パラメータ リストについてはまだ完全には読んでいませんが、IParameterList を使用してパラメータ タイプを注入する方法のようです。

編集:

これは次のように機能するように見えます:

ILog = kernel.Get<ILog>(new ConstructorArgument[] { 
    new ConstructorArgument("ClassName", this.GetType().Name) 
})

それからあなたはあなたのILogを持っています

class GenericLogger : Ilog
{
    GenericLogger(string ClassName) {};
}

私はこれをテストしませんでした.Ninjectソースからのものと思われるものです(最近のNinject2ツリーを見ています)

編集:

Parameter ではなく、ConstructorArgument を渡します。反映するように更新しました。

このコードは次を出力します: "Called From Init"

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);
    }
}

編集:

便利なもう 1 つの方法は、Bind().To().WithConstructorArgument() バインディングを使用することです。これは、自己バインディングまたは .WhenInjectedInto() 条件で使用する場合に役立ちます。

于 2009-04-05T18:24:46.317 に答える
0

カスタム プロバイダーのアイデアを詳しく説明するための簡単な方法を次に示します...

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; }    
于 2009-08-04T20:53:09.150 に答える