Qu'est-ce que Ninject et quand l'utilisez-vous?

j'ai aidé quelques amis sur un projet et il ya une classe qui utilise Ninject. Je suis assez nouveau à C# et je n'ai aucune idée de ce que fait cette classe, c'est pourquoi je dois comprendre Ninject. Est-ce que Quelqu'un peut expliquer ce Qu'est Ninject et quand l'utilise-t-on(Avec exemple si possible)? Ou si vous pouvez pointer vers certains liens qui seraient grands aussi.

j'ai essayé cette question: Ninject tutoriels / documentations? mais cela n'a pas vraiment aidé débutant comme moi.

52
demandé sur Community 2013-06-29 03:49:16

3 réponses

Ninject est la dépendance de l'injecteur .NET, la réalisation pratique du modèle d'Injection de Dépendance (formule d'Inversion de modèle de Contrôle).

supposons que vous ayez deux classes DbRepository et Controller :

class Controller {
   private DbRepository _repository;

   // ... some methods that uses _repository
}

class DbRepository {
   // ... some bussiness logic here ...
}

donc, maintenant vous avez deux problèmes:

  1. vous devez inialiser _repository pour l'utiliser. Vous avez de tels moyens:

    1. Dans le constructeur manuellement. Mais que faire si le constructeur de DbRepository change? Vous devez réécrire votre classe Controller parce que l'autre partie du code a été changée. Ce n'est pas difficile si vous avez seulement un Controller , mais si vous avez quelques classes qui ont une dépendance sur votre Repository vous avez un vrai problème.
    2. vous pouvez utiliser le Localisateur de service ou l'usine ou smth. Vous dépendez maintenant de votre Localisateur de service. Vous avez un localisateur de service global et tout le code doit l'utiliser. Comment allez-vous changer le comportement de localisateur de service lorsque vous devez utiliser dans une partie du code une logique d'activation et quelque chose d'autre dans une autre partie du code? Il n'y a qu'un seul moyen-le Localisateur de service passant par les constructeurs. Mais avec de plus en plus de classes, vous aurez besoin de passer de plus en plus. De toute façon, c'est bonne idée, mais c'est une mauvaise idée.

      class Controller {
         private DbRepository _repository;
      
         public Controller() {
           _repository = GlobalServiceLocator.Get<DbRepository>()
         }
      
         // ... some methods that uses _repository
      }
      
    3. vous pouvez utiliser l'injection de dépendance. Regardez le code:

      class Controller {
         private IRepository _repository;
      
         public Controller(IRepository repository) {
            _repository = repository;
         }
      }
      

    maintenant quand vous avez besoin de votre contrôleur vous écrivez: ninjectDevKernel.Get<Controller>(); ou ninjectTestKernel.Get<Controller>(); . Vous pouvez basculer entre des résolveurs de dépendances aussi vite que vous le voulez. Voir? C'est simple, vous n'avez pas besoin d'écrire beaucoup.

  2. vous ne pouvez pas faire de tests unitaires dessus. Votre Controller dépend de DbRepository et si vous voulez tester une méthode qui utilise le dépôt, votre code ira dans la base de données et lui demandera des données. C'est lent, très lent. Si votre code dans DbRepository change, votre test de l'unité sur Controller tombera. Seul le test d'intégration doit dire "problèmes" dans ce cas. Ce dont vous avez besoin dans les tests unitaires - pour isoler vos classes et tester une seule classe dans un test (dans l'idéal - une seule méthode). Si votre code DbRepository échoue, vous penserez que le code Controller a échoué - et c'est mauvais (même si vous avez des tests pour DbRepository et Controller - les deux échoueront et vous pouvez commencer à partir du mauvais endroit). Il faut un beaucoup de temps pour déterminer où est l'erreur vraiment. Vous devez savoir qu'un cours est ok, et qu'un autre cours a échoué.

  3. quand vous voulez remplacer DbRepository par quelque chose d'autre dans toutes vos classes, vous devez faire beaucoup de travail.

  4. Vous ne pouvez pas simple de contrôle de la durée de vie de DbRepository . Objet de cette classe crée lors de l'inialisation de Controller et supprime lorsque Controller supprime. Y il n'y a pas de partage entre les différentes instances de la classe Controller et il n'y a pas de partage entre les autres classes. Avec Ninject vous pouvez simplement écrire:

    kernel.Bind<IRepository>().To<DbRepository>().InSingletonScope();
    

Et la particularité de l'injection de dépendance - développement agile! Vous décrivez que votre contrôleur utilise un dépôt avec l'interface IRepository . Vous n'avez pas besoin d'écrire DbRepository , vous pouvez écrire simple MemoryRepository classe et de développer Controller tandis que d'autres gars développe DbRepository . Quand DbRepository sera terminé, vous réinditionnez simplement dans votre résolveur de dépendances que par défaut IRepository est DbRepository maintenant. Vous avez écrits beaucoup de contrôleurs? Tous utiliseront maintenant DbRepository . C'est cool.

lire la suite:

  1. Inversion de la commande (wiki)
  2. l'injection de Dépendance (wiki)
  3. Inversion de Contrôle des Conteneurs et l'Injection de Dépendance modèle (Martin Fowler)
45
répondu Viktor Lova 2014-12-18 03:21:39

Ninject est une Inversion de Contrôle conteneur.

Que fait-il?

supposons que vous ayez une classe Car qui dépend d'une classe Driver .

public class Car 
{
   public Car(IDriver driver)
   {
      ///
   }
}

pour utiliser la classe Car vous la construisez comme ceci:

IDriver driver = new Driver();
var car = new Car(driver);

un containter du CIO centralise les connaissances sur la façon de construire des classes. C'est un dépôt central qui sait quelques choses. Pour exemple, il sait que la classe de béton que vous devez utiliser pour construire une voiture est un Driver et non pas un autre IDriver .

Par exemple, si vous développez une application MVC, vous pouvez dire Ninject comment construire vos contrôleurs. Vous le faites en enregistrant les classes concrètes qui satisfont aux interfaces spécifiques. Au moment de L'exécution, Ninject va déterminer quelles classes sont nécessaires pour construire le contrôleur requis, et toutes les coulisses.

// Syntax for binding
Bind<IDriver>().To<Driver>();

c'est bénéfique parce qu'il vous permet de construire des systèmes qui sont plus facilement testables à l'unité. Supposons que Driver encapsule tous les accès à la base de données pour Car . Dans un test unitaire pour voiture, vous pouvez le faire:

IDriver driver = new TestDriver(); // a fake driver that does not go to the db
var car = new Car(driver);

il y a des cadres entiers qui prennent soin de créer automatiquement des classes de test pour vous et ils sont appelés cadres de moquerie.

pour plus d'informations:

38
répondu Sklivvz 2017-03-15 00:39:42

D'autres réponses sont excellentes, mais j'aimerais aussi souligner cet article Implementing Dependency Injection using Ninject .

C'est l'un des meilleurs articles que j'ai jamais lu qui explique L'Injection de dépendance et Ninject avec un exemple très élégant.

Voici l'extrait de l'article:

ci-dessous Interface sera mis en œuvre par notre (SMSService) et (MockSMSService), essentiellement la nouvelle Interface (ISMSService) exposera les mêmes comportements des deux services que le code ci-dessous:

public interface ISMSService
 {
 void SendSMS(string phoneNumber, string body);
 }

(SMSService) mise en œuvre de l'interface (ISMSService):

public class SMSService : ISMSService
 {
 public void SendSMS(string mobileNumber, string body)
 {
 SendSMSUsingGateway(mobileNumber, body);
 }




private void SendSMSUsingGateway(string mobileNumber, string body)
 {
 /*implementation for sending SMS using gateway*/
Console.WriteLine("Sending SMS using gateway to mobile: 
    {0}. SMS body: {1}", mobileNumber, body);
 }
 }

(MockSMSService) avec une implémentation totalement différente utilisant la même interface:

public class MockSMSService :ISMSService
 {
 public void SendSMS(string phoneNumber, string body)
 {
 SaveSMSToFile(phoneNumber,body);
 }

private void SaveSMSToFile(string mobileNumber, string body)
 {
 /*implementation for saving SMS to a file*/
Console.WriteLine("Mocking SMS using file to mobile: 
    {0}. SMS body: {1}", mobileNumber, body);
 }
 }

nous devons implémenter un changement à notre constructeur de classe (UIHandler) pour passer la dépendance ce faisant, le code qui utilise le (UIHandler) peut déterminer quelle mise en œuvre concrète de (ISMSService) utiliser:

public class UIHandler
 {
 private readonly ISMSService _SMSService;

public UIHandler(ISMSService SMSService)
 {
 _SMSService = SMSService;
 }
 public void SendConfirmationMsg(string mobileNumber) {

 _SMSService.SendSMS(mobileNumber, "Your order has been shipped successfully!");
 }
 }

maintenant, nous devons créer une classe séparée (NinjectBindings) qui hérite de (NinjectModule). Cette classe sera responsable de résoudre les dépendances au moment de l'exécution, puis nous passerons outre l'événement de charge qui est utilisé pour configurer la liaison en elle. La bonne chose à propos de Ninject est que nous n'avons pas besoin de changer notre code (ISMSService), (SMSService), et (MockSMSService).

public class NinjectBindings : Ninject.Modules.NinjectModule
 {
 public override void Load()
 {
 Bind<ISMSService>().To<MockSMSService>();
 }
 }

maintenant dans le code de forme D'UI, nous allons utiliser la liaison pour Ninject qui déterminera quelle implémentation utiliser:

class Program
 {
 static void Main(string[] args)
 {
 IKernel _Kernal = new StandardKernel();
 _Kernal.Load(Assembly.GetExecutingAssembly());
 ISMSService _SMSService = _Kernal.Get<ISMSService>();

UIHandler _UIHandler = new UIHandler(_SMSService);
 _UIHandler.SendConfirmationMsg("96279544480");

Console.ReadLine();
 }
 }

maintenant le code utilise le noyau Ninject pour résoudre toutes les chaînes de dépendances, si nous voulons utiliser le service réel (SMSService) en mode Release (sur l'environnement de production) au lieu du mock one, nous devons changer sur la classe de liaison Ninject (NinjectBindings) à utiliser uniquement le droit de la mise en œuvre ou en utilisant le #if DEBUG directive comme ci-dessous:

public class NinjectBindings : Ninject.Modules.NinjectModule
 {
 public override void Load()
 {
#if DEBUG
 Bind<ISMSService>().To<MockSMSService>();
#else
 Bind<ISMSService>().To<SMSService>();
#endif

}
 }

maintenant notre classe de reliure (NinjectBindings) vit sur le dessus de tout notre code d'exécution et nous pouvons contrôler la configuration facilement en un seul endroit.


Voir aussi Qu'est-ce que L'Inversion de la commande? quelques exemples très simples sont mentionnés pour comprendre la COI.

5
répondu JerryGoyal 2017-05-23 11:55:07