2010-02-09 4 views
61

J'ai décidé de commencer à utiliser Ninject et de faire face à un problème. Dites que j'ai le scénario suivant. J'ai une interface IService et 2 classes implémentant cette interface. Et aussi j'ai une classe, qui a un constructeur obtenant IService et un int. Comment puis-je créer une instance de cette classe avec Ninject (je ne veux pas hardwire cet int, je veux le passer chaque fois que je reçois une instance)?Création d'une instance en utilisant Ninject avec des paramètres supplémentaires dans le constructeur

est ici un code illustrant la situation:

interface IService 
{ 
    void Func(); 
} 

class StandardService : IService 
{ 
    public void Func() 
    { 
     Console.WriteLine("Standard"); 
    } 
} 

class AlternativeService : IService 
{ 
    public void Func() 
    { 
     Console.WriteLine("Alternative"); 
    } 
} 


class MyClass 
{ 
    public MyClass(IService service, int i) 
    { 
     this.service = service; 
    } 

    public void Func() 
    { 
     service.Func(); 
    } 

    IService service = null; 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     IKernel kernel = new StandardKernel(new InlineModule(
      x => x.Bind<IService>().To<AlternativeService>(), 
      x => x.Bind<MyClass>().ToSelf())); 

     IService service = kernel.Get<IService>(); 

     MyClass m = kernel.Get<MyClass>(); 
     m.Func(); 
    } 
} 

Répondre

84

Le With.ConstructorArgument existait dans 1,0 à cet effet. En 2.0, la syntaxe a changé légèrement: - With.Parameters.ConstructorArgument with ninject 2.0

Voir Inject value into injected dependency pour plus de détails et des exemples de la façon d'utiliser le contexte, les fournisseurs et les arguments pour passer des trucs comme ça autour de plus correctement.

EDIT: Comme Steven a choisi de faire semblant mon commentaire est hors de propos, je ferais mieux de faire clairement ce que je veux dire, avec quelques exemples (pour 2.0):

MyClass m = kernel.Get<MyClass>(new ConstructorArgument("i", 2)); 

qui à mes yeux est très clair et déclare exactement ce qui se passe.

Si vous êtes dans une position où vous pouvez déterminer le paramètre d'une manière plus globale, vous pouvez enregistrer un fournisseur et faire comme ceci:

class MyClassProvider : SimpleProvider<MyClass> 
{ 
    protected override MyClass CreateInstance(IContext context) 
    { 
     return new MyClass(context.Kernel.Get<IService>(), CalculateINow()); 
    } 
} 

Et inscrivez-vous comme ceci:

x => x.Bind<MyClass>().ToProvider(new MyClassProvider()) 

NB le bit CalculateINow() est l'endroit où vous mettriez votre logique comme dans la première réponse.

Ou le rendre plus complexe comme celui-ci:

class MyClassProviderCustom : SimpleProvider<MyClass> 
{ 
    readonly Func<int> _calculateINow; 
    public MyClassProviderCustom(Func<int> calculateINow) 
    { 
     _calculateINow = calculateINow; 
    } 

    protected override MyClass CreateInstance(IContext context) 
    { 
     return new MyClass(context.Kernel.Get<IService>(), _calculateINow()); 
    } 
} 

qui vous souhaitez enregistrer comme ceci:

x => x.Bind<MyClass>().ToProvider(new MyClassProviderCustom(() => new Random().Next(9))) 

MISE À JOUR: mécanismes récents qui présentent des modèles beaucoup améliorés avec moins que le passe-partout ci-dessus sont incorporé dans l'extension Ninject.Extensions.Factory, voir: https://github.com/ninject/ninject.extensions.factory/wiki

Comme indiqué précédemment, if you need to pass a different parameter each time and you have multiple levels in the dependency graph, you might need to do something like this.

Une dernière considération est que parce que vous n'avez pas spécifié Using<Behavior>, il va par défaut la valeur par défaut comme spécifié/fait défaut dans les options du noyau (TransientBehavior dans l'échantillon) qui pourrait rendre fait que l'usine calcule i à la volée moot [par exemple, si l'objet était en cache]

Maintenant, pour clarifier d'autres points dans les commentaires qui sont FUDed et glosés. Certaines choses importantes à prendre en compte sur l'utilisation de DI, que ce soit Ninject ou tout autre chose est de:

  1. ont autant que possible fait par injection constructeur de sorte que vous ne avez pas besoin d'utiliser des attributs spécifiques des conteneurs et des astuces.Il y a un bon article sur ce blog qui s'appelle Your IoC Container is Showing.

  2. Réduire le code allant au conteneur et demander des informations - sinon votre code est couplé à a) le conteneur spécifique (que la CSL peut minimiser) b) la manière dont votre projet entier est présenté. Il y a de bons articles sur ce blog montrant que CSL ne fait pas ce que vous pensez. Ce sujet général est appelé Service Location vs Dependency Injection. MISE À JOUR: Voir http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx pour une justification détaillée et complète.

  3. Réduire au minimum l'utilisation des singletons et

    statics
  4. Ne présumez pas il n'y a qu'un seul conteneur [global] et qu'il est bon de simplement demander chaque fois que vous en avez besoin comme une belle variable globale. L'utilisation correcte de plusieurs modules et Bind.ToProvider() vous donne une structure pour gérer cela. De cette façon, chaque sous-système distinct peut travailler seul et vous avez l'habitude de composants de bas niveau étant liés à des composants de haut niveau, etc.

Si quelqu'un veut remplir les liens vers les blogs dont je parle J'apprécierais (ils sont tous déjà liés à partir d'autres messages sur SO, donc tout ceci n'est qu'une duplication que j'ai introduite dans le but d'éviter la confusion d'une réponse trompeuse.)

Maintenant , si seulement Joel pouvait entrer et me mettre vraiment sur la bonne syntaxe et/ou la bonne façon de faire ça!

MISE À JOUR: Bien que cette réponse est clairement utile du nombre de upvotes il est engrangé, je voudrais faire les recommandations suivantes:

  • Le sent ci-dessus comme il est un peu daté et pour être honnête reflète une Beaucoup de pensée incomplète qui semble presque embarrassante depuis la lecture Dependency Injection in .net - Courez et achetez maintenant - il ne s'agit pas seulement de DI, la première moitié est un traitement complet de toutes les préoccupations d'architecture qui l'entourent d'un homme qui a passé beaucoup trop de temps ici suspendu autour de l'étiquette d'injection de dépendance.
  • Allez lire Mark Seemann's top rated posts here on SO right now - vous apprendrez des techniques précieuses de tous
+0

Bon à trouver, puisque la documentation est si loin derrière .... – Elton

Questions connexes