Je suis assez à l'aise avec l'injection de dépendances à l'aide de NInject dans MVC3. Tout en travaillant dans une application MVC3, j'ai développé une usine de création de contrôleur personnalisée à l'aide de NInject, de sorte que tout contrôleur créé aura des dépendances injectées via cette usine de contrôleur.
Maintenant, je commence à développer une application Windows, je veux utiliser l'injection de dépendance à l'échelle de l'application. c'est-à-dire que chaque objet doit être créé via NInject, afin de faciliter les tests unitaires. Veuillez me guider pour vous assurer que chaque objet créé doit passer par la NInject Factory uniquement.
Par exemple, si sur un formulaire Windows sur un Button_Click
événement, j'écris:
TestClass testClass = new TestClass()
et TestClass
a une dépendance sur, disons, ITest
alors il doit être automatiquement résolu. Je sais que je peux utiliser:
Ikernel kernel = new StandardKenel()
//AddBinding()
TestClass testClass = kenel.get<TestClass>();
Mais je trouve cela fastidieux de le faire chaque fois que je veux créer un objet. Cela oblige également le développeur à créer l'objet d'une manière particulière. Peut-il être amélioré?
Puis-je avoir un référentiel central pour la création d'objets et chaque création d'objet utilisera automatiquement ce référentiel?
la source
Réponses:
Pour les applications clientes, il est souvent préférable d'adapter un modèle comme MVP (ou MVVM) et d'utiliser la liaison de données du formulaire au ViewModel ou au Presenter sous-jacent.
Pour les ViewModels, vous pouvez injecter les dépendances requises à l'aide de l'injection de constructeur standard.
Dans la racine de composition de votre application, vous pouvez câbler le graphique d'objet entier pour votre application. Vous n'avez pas besoin d'utiliser un conteneur DI (tel que Ninject) pour cela, mais vous pouvez.
la source
Les applications Windows Forms ont généralement un point d'entrée qui ressemble à ceci:
Si vous faites de ce point dans le code votre racine de composition , vous pouvez considérablement réduire le nombre d'emplacements où vous avez du code invoquant explicitement Ninject comme s'il s'agissait d'un localisateur de service.
À partir de ce point, vous injectez toutes vos dépendances via l'injection de constructeur.
Si votre "dépendance" est quelque chose dont vous avez besoin pour pouvoir produire plusieurs fois, alors ce dont vous avez vraiment besoin est une usine:
Vous pouvez implémenter l'interface IFactory de cette façon pour éviter d'avoir à créer une tonne d'implémentations uniques:
la source
InjectionFactory<T>
implémentées, alors le code fourni devrait fonctionner très bien. Y a-t-il quelque chose en particulier avec lequel vous rencontrez des problèmes?Type
, mais qui garantirait que les objets qu'il hydrate pour cetType
implémentation ou étendent un type générique donné. Rien de bien spécial.J'écris toujours un wrapper d'adaptateur pour tout conteneur IoC, qui ressemble à ceci:
Pour Ninject, en particulier, la classe Adapter concrète ressemble à ceci:
La principale raison pour cela est d'abstraire le cadre IoC, donc je peux le remplacer à tout moment - étant donné que la différence entre les cadres est généralement dans la configuration plutôt que dans l'utilisation.
Mais, en prime, les choses deviennent également beaucoup plus faciles pour l'utilisation du cadre IoC dans d'autres cadres qui ne le supportent pas de manière inhérente. Pour WinForms, par exemple, il s'agit de deux étapes:
Dans votre méthode Main, instanciez simplement un conteneur avant de faire autre chose.
Et puis avoir une forme de base, dont dérivent d'autres formes, qui appelle Injecter sur elle-même.
Cela indique à l'heuristique de câblage automatique de tenter d'injecter récursivement toutes les propriétés du formulaire qui correspondent aux règles définies dans vos modules.
la source
Une bonne utilisation de l'injection de dépendance repose généralement sur la séparation du code qui crée les objets et la logique métier réelle. En d'autres termes, je ne voudrais pas que mon équipe utilise
new
et crée fréquemment une instance d'une classe de cette façon. Une fois cela fait, il n'y a aucun moyen de remplacer facilement ce type créé par un autre, car vous avez déjà spécifié le type de béton.Il y a donc deux façons de résoudre ce problème:
TestClass
dans votre Windows Form afin qu'il ait déjà une instance quand il en a besoin. Lorsque Ninject instancie votre formulaire, il crée automatiquement la dépendance.IKernel
dans votre formulaire Windows, puis l'utiliser pour instancierTestClass
. En fonction de votre style, il existe également d'autres moyens d'y parvenir (injection d'une classe d'usine, délégué d'usine, etc.).Cela permet d'échanger facilement à la fois le type concret de TestClass, ainsi que de modifier la construction réelle de la classe de test, sans réellement modifier le code qui utilise la classe de test.
la source
Je n'ai pas utilisé Ninject, mais la façon standard de créer des choses lorsque vous utilisez un IoC est de le faire via un
Func<T>
oùT
est le type d'objet que vous souhaitez créer. Donc, si l'objetT1
doit créer des objets de type,T2
le constructeur deT1
doit avoir un paramètre de typeFunc<T1>
qui est ensuite stocké en tant que champ / propriété deT2
. Maintenant , quand vous voulez créer des objets de typeT2
àT1
vous invoquez laFunc
.Cela vous dissocie totalement de votre infrastructure IoC et est la bonne façon de coder dans un état d'esprit IoC.
L'inconvénient de cela est qu'il peut devenir ennuyeux lorsque vous devez câbler manuellement un
Func
exemple ou lorsque votre créateur a besoin de certains paramètres, de sorte que l'IoC ne peut pas câbler automatiquement leFunc
pour vous.http://code.google.com/p/autofac/wiki/RelationshipTypes
la source