2011-07-01 2 views
19

J'ai des drapeaux globaux qui activent/désactivent les fonctionnalités. Je voudrais injecter des dépendances en fonction d'un drapeau. Certaines fonctionnalités nécessitent des classes qui sont fortement construites, donc je veux injecter null si la valeur de l'indicateur est false et la dépendance réelle sinon. Ninject ne permet pas l'injection de null. Il y a-t-il des alternatives?Ninject. Injection optionnelle

Mise à jour: les arguments du constructeur peuvent être décorés avec l'attribut OptionalAttribute. Dans ce cas, nul est injecté s'il n'y a pas de liaison correspondante trouvée. Il y a un problème ici: je ne peux pas vérifier si la classe cible peut être correctement construite. J'ai un test pour chaque dépendance publique qui vérifie si elle peut être construite avec succès. Dans le cas où la valeur de l'indicateur est vrai, je ne serai pas en mesure de trouver l'erreur lorsque la dépendance décorée avec l'attribut OptionalAttribute, ne peut pas être construite correctement. Je voudrais le gérer uniquement au niveau de la reliure.

Répondre

17

Vous pouvez modifier le comportement d'injection en liant à l'aide d'une méthode usine (c'est-à-dire ToMethod), et il est possible d'autoriser l'injection de valeurs nulles en configurant le paramètre AllowNullInjection du conteneur.

Une autre alternative serait d'utiliser une méthode d'usine et de fournir un objet factice léger au lieu de votre classe de poids lourds. Si vous utilisez des interfaces ce serait simple, il suffit d'avoir des implémentations de l'interface qui ne font rien. Vous pouvez même utiliser un cadre moqueur comme FakeItEasy pour construire ces mannequins pour vous. L'avantage ici est que le mannequin rend le comportement transparent spécial aux clients iE clients ne ont pas besoin de vérifier null, etc.

Un exemple d'utiliser une méthode de fabrication, plus AllowNullInjection et nulls:

public void Configure() 
{ 
    bool create = true; 

    IKernel kernel = new StandardKernel(); 

    kernel.Settings.AllowNullInjection = true; 

    kernel.Bind<IFoo>().ToMethod(ctx => create ? ctx.Kernel.Get<Foo>() : null); 

    DependendsOnIFoo depFoo = kernel.Get<DependendsOnIFoo>(); 
} 

private interface IFoo {} 

private class Foo : IFoo {} 

private class DependendsOnIFoo 
{ 
    public DependendsOnIFoo(IFoo foo) {} 
} 

Et un exemple où un objet léger est substitué en fonction du drapeau:

public void Configure() 
{ 
    bool heavy = true; 

    IKernel kernel = new StandardKernel(); 

    kernel.Bind<IFoo>() 
    .ToMethod(ctx => heavy ? ctx.Kernel.Get<HeavyFoo>() : (IFoo)new DummyFoo()); 

    DependendsOnIFoo depFoo = kernel.Get<DependendsOnIFoo>(); 
} 

private interface IFoo {} 

private class HeavyFoo : IFoo {} 

private class DummyFoo : IFoo { } 

private class DependendsOnIFoo 
{ 
    public DependendsOnIFoo(IFoo foo) {} 
} 
12

Injecter null est généralement pas une bonne idée. Cela pollue votre code avec vérifie si l'objet est nul ou non comme le montre le code suivant:

public interface IFoo 
{ 
    void Do(); 
} 

public class Foo : IFoo 
{ 
    public void Do() 
    { 
     DoSomething(); 
    } 
} 

public class UglyNullCheckingBar 
{ 
    IFoo foo; 
    public Bar(IFoo foo) 
    { 
     this.foo = foo; 
    } 

    public void Do() 
    { 
     if (this.foo != null) 
     { 
      this.foo.Do(); 
     } 
    } 
} 

La meilleure façon dans ce cas est de mettre en œuvre un objet nul qui ne fait absolument rien et injecter celui-ci au lieu de nul. Cela garde votre code propre.

public class NullFoo : IFoo 
{ 
    public void Do() {} 
} 

public class Bar 
{ 
    IFoo foo; 
    public Bar(IFoo foo) 
    { 
     this.foo = foo; 
    } 

    public void Do() 
    { 
     this.foo.Do(); 
    } 
} 
Questions connexes