Question

J'utilise C # avec le cadre d'unité de Microsoft. Je ne sais pas trop comment résoudre ce problème. Cela a probablement quelque chose à voir avec mon manque de compréhension de l'unité.

Mon problème peut être résumé en utilisant l'exemple de code suivant:

class Train(Person p) { ... }

class Bus(Person p) { ... }

class Person(string name) { ... }

Person dad = new Person("joe");
Person son = new Person("timmy");

Lorsque j'appelle la méthode Resolve sur le bus, comment puis-je être sûr que la personne «fils» avec le nom «Timmy» est injectée et lors de la résolution de train, comment puis-je être sûr que cette personne «papa» avec le nom «Joe» est résolue?

Je pense que peut-être utiliser des instances nommées? Mais je suis à court. Toute aide serait appréciée.

En passant, je préfère ne pas créer une interface Iperson.

Était-ce utile?

La solution

Une façon de résoudre ce problème serait d'utiliser un constructeur d'injection avec un enregistrement nommé.

// Register timmy this way  
Person son = new Person("Timmy");  
container.RegisterInstance<Person>("son", son);  

// OR register timmy this way  
container.RegisterType<Person>("son", new InjectionConstructor("Timmy"));  

// Either way, register bus this way.  
container.RegisterType<Bus>(new InjectionConstructor(container.Resolve<Person>("son")));  

// Repeat for Joe / Train

Autres conseils

Sauf si vous vous inscrivez respectivement "Joe" et "Timmy" comme des dépendances nommées, vous ne pouvez pas être sûr que "Timmy" est injecté dans SchoolBus. En fait, si vous essayez d'enregistrer deux instances de la même classe que les dépendances sans nom, vous aurez une configuration ambiguë et vous ne pourrez pas résoudre Person du tout.

En général, si vous devez enregistrer de nombreuses instances nommées, vous faites probablement de DI dans le mauvais sens. L'idée principale de DI est de résoudre Services de domaine plus que Objets de domaine.

L'idée principale de DI est de fournir un mécanisme qui vous permet de résoudre types abstraits (interfaces ou classes abstraites) en types de béton. Votre exemple n'a pas de types abstraits, donc il n'a pas vraiment de sens.

Mark Seeman a bien compris. Et je sympathise avec votre confusion. Je l'ai traversé moi-même lorsque j'ai appris à utiliser des conteneurs d'injection de dépendance automatique. Le problème est qu'il existe de nombreuses façons valides et raisonnables de concevoir et d'utiliser des objets. Pourtant, seules certaines de ces approches fonctionnent avec des conteneurs d'injection automatique de dépendance.

Mon histoire personnelle: j'ai appris les principes OO de la construction d'objets et l'inversion du contrôle bien avant d'avoir appris à utiliser l'inversion de conteneurs de contrôle comme les conteneurs Unity ou Castle Windsor. J'ai acquis l'habitude d'écrire du code comme ceci:

public class Foo
{
   IService _service;
   int _accountNumber;

   public Foo(IService service, int accountNumber)
   {
      _service = service;
      _accountNumber = accountNumber;
   }
   public void SaveAccount()
   {
       _service.Save(_accountNumber);

   }
}
public class Program
{
     public static void Main()
     {
        Foo foo = new Foo(new Service(),1234);
        foo.Save();
     }
}

Dans cette conception, ma classe FOO est responsable de l'enregistrement des comptes dans la base de données. Il a besoin d'un numéro de compte pour le faire et un service pour faire le sale boulot. Ceci est quelque peu similaire aux classes concrétisées que vous avez fournies ci-dessus, où chaque objet prend des valeurs uniques dans le constructeur. Cela fonctionne bien lorsque vous instanciez les objets avec votre propre code. Vous pouvez passer dans les valeurs appropriées au bon moment.

Cependant, lorsque j'ai appris les conteneurs automatique des injections de dépendance, j'ai constaté que je n'insturais plus FOO à la main. Le conteneur instancierait les arguments du constructeur pour moi. C'était une grande commodité pour les services comme Iservice. Mais cela ne fonctionne évidemment pas si bien pour les entiers et les cordes et autres. Dans ces cas, il fournirait une valeur par défaut (comme zéro pour un entier). Au lieu de cela, j'avais été habitué à transmettre des valeurs spécifiques au contexte comme le numéro de compte, le nom, etc ... J'ai donc dû ajuster mon style de codage et de conception pour ressembler à ceci:

public class Foo
{
   IService _service;
   public Foo(IService service)
   {
      _service = service;
   }
   public void SaveAccount(int accountNumber)
   {
       _service.Save(accountNumber);

   }
}
public class Program
{
     public static void Main()
     {
        Foo foo = new Foo(new Service());
        foo.Save(1234);
     }
}

Il semble que les deux classes FOO soient des conceptions valides. Mais le second est utilisable avec l'injection automatique de dépendance, et le premier ne l'est pas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top