web-dev-qa-db-fra.com

Comment passer un paramètre au constructeur en utilisant Simple Injector?

L'injecteur simple vous permet-il de passer des paramètres au constructeur lorsque vous résolvez? Je voudrais savoir si ces deux cadres font ce que font ResolverOverride ou DependencyOverride d'Unity.

24
Ray

Je soupçonne que cette question concerne la transmission de valeurs primitives au constructeur au moment où le service est réellement résolu.

Créons une classe de test simple:

public interface IFoo
{

}

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

    }
}

La classe Foo prend un argument de chaîne que nous aimerions fournir lors de la résolution du service 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");

Si nous voulons pouvoir créer de nouvelles instances de la classe Foo sans utiliser directement le conteneur, nous pouvons simplement injecter un délégué de fonction.

public interface IBar { }

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

La "racine de composition" ressemble maintenant à ceci:

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

Si la question concerne la transmission d'une valeur primitive "statique" au constructeur, cela se fait simplement en enregistrant un délégué d'usine comme celui-ci.

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

La différence est que cette approche ne vous permet pas de passer une valeur au moment de la résolution. La valeur est spécifiée statiquement au moment de l'enregistrement.

26
seesharper

L'option la plus simple avec Simple Injector est probablement de s'inscrire auprès d'un délégué

[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)
    {
    }
}

Une option avancée pour l'injection de dépendances primitives est détaillée ici

20
qujck

Ce qui précède fonctionnera tous si votre constructeur n'a pas d'autres dépendances (ou si vous souhaitez résoudre ces dépendances manuellement). Si vous avez le scénario ci-dessous bien qu'il tombe:

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

Maintenant, vous devez non seulement injecter manuellement la chaîne mais aussi Foo. Alors maintenant, vous n'utilisez pas du tout l'injection de dépendance (vraiment). État de l'injecteur simple également:

L'injecteur simple ne permet pas d'injecter des types primitifs (tels que des entiers et des chaînes) dans des constructeurs.

Ma lecture de ceci est qu'ils disent "ne fais pas ça".

Points d'extensibilité

Une autre option consiste à utiliser "Points d'extensibilité" pour ce scénario .

Pour ce faire, vous devez extraire vos éléments codés en dur de vos éléments injectés:

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

  public void Init(string parameter)
  {

  }
}

Vous pouvez maintenant injecter vos dépendances et vos éléments codés en dur:

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

Si vous ajoutez maintenant une autre dépendance, votre injection fonctionnera maintenant sans que vous ayez à mettre à jour la configuration, c'est-à-dire que votre code est toujours bien découplé:

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