2010-04-19 15 views
5

Lorsque vous utilisez Ninjects ConstructorArgument, vous pouvez spécifier la valeur exacte à injecter pour des paramètres spécifiques. Pourquoi cette valeur ne peut-elle pas être nulle ou comment puis-je la faire fonctionner? Peut-être que ce n'est pas quelque chose que vous aimeriez faire, mais je veux l'utiliser dans mes tests unitaires .. Exemple:Pourquoi ne puis-je pas injecter la valeur null avec Ninjects ConstructorArgument?

public class Ninja 
{ 
    private readonly IWeapon _weapon; 
    public Ninja(IWeapon weapon) 
    { 
     _weapon = weapon; 
    } 
} 

public void SomeFunction() 
{ 
    var kernel = new StandardKernel(); 
    var ninja = kernel.Get<Ninja>(new ConstructorArgument("weapon", null)); 
} 
+0

Je ne suis pas familier avec ninject, mais je pense que le problème est que IoC-conteneur utilise des informations de type pour trouver un constructeur approprié et il ne peut pas le trouver par la valeur nulle. Vous feriez mieux de chercher une réponse dans la documentation ou dans son code. Dans une bibliothèque que j'ai utilisé l'instance de l'objet Type correspondant doit être passé à la place de null. Il pourrait y avoir une solution similaire ici aussi. – SergGr

+0

Merci monsieur :-) – stiank81

Répondre

7

regardant la source (et la trace de la pile, je suis arrivé par reproing que vous omettez: P)

C'est parce qu'il est la liaison à une autre surcharge du ConstructorArgument cteur que l'utilisation normale (où vous re passer un type de valeur ou un type de référence non nul).

La solution est de lancer le nul à l'objet: -

var ninja = kernel.Get<Ninja>(new ConstructorArgument("weapon", (object)null)); 

source de Ninject 2:

public class ConstructorArgument : Parameter 
{ 
    /// <summary> 
    /// Initializes a new instance of the <see cref="ConstructorArgument"/> class. 
    /// </summary> 
    /// <param name="name">The name of the argument to override.</param> 
    /// <param name="value">The value to inject into the property.</param> 
    public ConstructorArgument(string name, object value) : base(name, value, false) { } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="ConstructorArgument"/> class. 
    /// </summary> 
    /// <param name="name">The name of the argument to override.</param> 
    /// <param name="valueCallback">The callback to invoke to get the value that should be injected.</param> 
    public ConstructorArgument(string name, Func<IContext, object> valueCallback) : base(name, valueCallback, false) { } 
} 

Repro:

public class ReproAndResolution 
{ 
    public interface IWeapon 
    { 
    } 

    public class Ninja 
    { 
     private readonly IWeapon _weapon; 
     public Ninja(IWeapon weapon) 
     { 
      _weapon = weapon; 
     } 
    } 

    [Fact] 
    public void TestMethod() 
    { 
     var kernel = new StandardKernel(); 
     var ninja = kernel.Get<Ninja>(new ConstructorArgument("weapon", (object)null)); 
    } 
} 

leçon? Vous seriez fou de ne pas télécharger la dernière source et regardez-le. Super commentaires, bonne base de code propre. Merci encore à Ian Davis pour cette astuce/aiguillon!

+0

+1 Nice - choses intéressantes. – Finglas

+0

Thx pour l'explication. Je ne pense pas que je veuille faire le tour des objets nuls, mais cela semble répondre à ma question! Peut-être que je dois vérifier la dernière source :-) – stiank81

+0

@ stiank81: Comme mon commentaire sur la réponse de @Finglas (qui je crois est la bonne réponse, même si je suis d'accord, cela devrait être Accepté: P) dit, la raison pour laquelle il est moche est parce que ce n'est pas destiné à être fait dans l'utilisation normale (N'a pas couvert CoveructorArgument étant une mauvaise approche par défaut dans une autre question?: P) @Finglas: Merci, et merci de supprimer les autres choses –

0

Ceci est probablement non pris en charge parce que les arguments du constructeur peuvent être les types de valeur aussi.

+0

Cela m'a incité à trouver la vraie réponse car elle se sentait mal. Mais cela m'a aussi incité à réfléchir pour ne pas être d'accord avec la réponse de Brian (je laisserais les deux + mais trop tard pour défaire l'autre et même si tous les deux ont fourni un aperçu conceptuel, je ne crois pas qu'ils représentent quelque chose que Ninject force) –

3

Je ne sais pas Ninject, mais l'injection de constructeurs AFAIK est couramment utilisée pour les dépendances obligatoires et donc null a peu de sens dans ce contexte. Si la dépendance n'est pas obligatoire, le type doit fournir un constructeur par défaut et utiliser l'injection de propriété à la place.

This post fournit des informations supplémentaires.

+0

I + 1d cela parce que cela semblait plus logique que la réponse de Gerrie.À la réflexion, je ne suis pas vraiment d'accord, car il peut être utilisé pour les types de valeur ainsi que les types de référence et le point ne généralise pas vraiment bien dans ce contexte. Ce que l'on veut protéger est non spécifié, aléatoirement non initialisé et/ou dépendances qui ne sont pas spécifiées d'une manière claire que les outils peuvent vous aider à identifier les chaînes de dépendance. –

+0

L'injection de propriété est une solution acceptable pour cela? Si oui, cela semble être une chose raisonnable à faire. Merci pour le lien. – stiank81

+0

@ stiank81: Bien que l'injection de propriété puisse accomplir la chose de base que vous essayez d'obtenir (beaucoup de valeurs 'null'), ce faisant, vous allez perdre beaucoup de temps dans la propreté du code, donc je dirais non - je vous référer à la réponse de @Finglas. –

3

Je veux l'utiliser dans mon unité teste

Il est no need to use an IOC container for unit tests. Vous devriez utiliser le conteneur pour câbler votre application ensemble au moment de l'exécution, et rien de plus. Et si cela commence à faire du mal, son une odeur indiquant votre classe devient hors de la main

Votre test unitaire serait alors dans cet exemple (violation SRP?):

var ninja = new Ninja(null); 

Ce qui précède est legit code C# , et en passant une référence nulle pour les tests unitaires est une façon parfaitement valide de tester les zones qui n'ont pas besoin de la dépendance.

+0

+ 1 point important même s'il ne répond pas la question (bien que le fait que cela soit le cas est probablement la raison pour laquelle ce problème (résoudre une erreur de surcharge en cas de 'null') n'a pas été considéré comme un problème –

+0

@Ruben: C'est bien, en plus de ça, c'est ça Améliorer et apprendre. – Finglas