web-dev-qa-db-ja.com

Simple Injectorを使用してコンストラクターにパラメーターを渡すにはどうすればよいですか?

Simple Injectorでは、解決時にコンストラクターにパラメーターを渡すことができますか?これらのフレームワークの両方がUnityのResolverOverrideまたはDependencyOverrideの両方を実行するかどうかを知りたいのですが。

24
Ray

この質問は、サービスが実際に解決されるときにコンストラクターにプリミティブ値を渡すことに関するものだと思います。

簡単なテストクラスを設定しましょう:

public interface IFoo
{

}

public class Foo : IFoo
{
    public Foo(string value)
    {

    }
}

Fooクラスは、IFooサービスを解決するときに指定する文字列引数を取ります。

var container = new ServiceContainer();
container.Register<string, IFoo>((factory, value) => new Foo(value));
var firstFoo = container.GetInstance<string, IFoo>("SomeValue");
var secondFoo = container.GetInstance<string, IFoo>("AnotherValue");

コンテナーを直接使用せずにFooクラスの新しいインスタンスを作成できるようにするには、関数デリゲートを挿入するだけです。

public interface IBar { }

public class Bar : IBar
{
    public Bar(Func<string, IFoo> fooFactory)
    {
        var firstFoo = fooFactory("SomeValue");
        var secondFoo = fooFactory("AnotherValue");
    }
}

「コンポジションルート」は次のようになります。

var container = new ServiceContainer();
container.Register<string, IFoo>((factory, value) => new Foo(value));
container.Register<IBar, Bar>();
var bar = container.GetInstance<IBar>();

質問が「静的な」プリミティブ値をコンストラクタに渡すことに関するものである場合、これは、このようにファクトリデリゲートを登録することで簡単に行えます。

var container = new ServiceContainer();
container.Register<IFoo>((factory) => new Foo("SomeValue"));
var firstInstance = container.GetInstance<IFoo>();
var secondInstance = container.GetInstance<IFoo>();

違いは、この方法では解決時に値を渡せないことです。値は登録時に静的に指定されます。

26
seesharper

おそらく Simple Injector の最も簡単なオプションはデリゲートに登録することです

[Test]
public void Test1()
{
    Container container = new Container();

    container.Register<IClassWithParameter>(() => new ClassWithParameter("SomeValue"));

    var result = container.GetInstance<IClassWithParameter>();
}

public interface IClassWithParameter { }

public class ClassWithParameter : IClassWithParameter
{
    public ClassWithParameter(string parameter)
    {
    }
}

プリミティブの依存関係を注入するための詳細オプションは詳細 here

20
qujck

上記は、コンストラクターに他の依存関係がない場合(またはこれらの依存関係を手動で解決する場合)に機能します。それが落ちるが、以下のシナリオがある場合:

public class Test : ITest
{
   private IFoo _foo;
   public Test(string parameter, IFoo foo)
   {
      _foo = foo;
      ....
   }
}

これで、手動で文字列を挿入するだけでなく、Fooも挿入する必要があります。したがって、依存関係注入をまったく使用していません(本当に)。また、シンプルインジェクターの状態:

Simple Injectorでは、プリミティブ型(整数や文字列など)をコンストラクターに注入することはできません。

私のこれを読むと、彼らは「これをしないでください」と言っています。

拡張ポイント

ここでのもう1つのオプションは このシナリオでは「拡張ポイント」 を使用することです。

これを行うには、注入された要素からハードコードされた要素を抽象化する必要があります。

public class Test : ITest
{
   private IFoo _foo;
   public Test(IFoo foo)
   {
      _foo = foo;
      ....
   }

  public void Init(string parameter)
  {

  }
}

これで、依存関係およびをハードコードされた要素に挿入できます。

_container.Register<ITest, Test>();
_container.RegisterInitializer<Test>(instance => {instance.Init("MyValue");});

別の依存関係を追加すると、構成を更新しなくてもインジェクションが機能するようになります。つまり、コードは適切に分離されています。

public class Test : ITest
{
   private IFoo _foo;
   private IBar _bar;
   public Test(IFoo foo, IBar bar)
   {
      _foo = foo;
      _bar = bar;
      ....
   }

  public void Init(string parameter)
  {

  }
}
8
Liam