2010-04-19 8 views
5

Wenn Sie Ninjects ConstructorArgument verwenden, können Sie den genauen Wert für bestimmte Parameter angeben. Warum kann dieser Wert nicht null sein, oder wie kann ich es funktionieren lassen? Vielleicht ist es nicht etwas, was Sie tun möchten, aber ich will es in meinen Unit-Tests verwenden .. Beispiel:Warum kann ich mit Ninjects ConstructorArgument keinen Wert null injizieren?

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

Ich bin nicht vertraut mit Ninject, aber ich denke, das Problem ist, dass IoC-Container Typ Informationen verwendet, um einen geeigneten Konstruktor zu finden, und es kann nicht durch Null-Wert herausfinden. Sie sollten besser in der Dokumentation oder im Code nach Antworten suchen. In einer Bibliothek, die ich Instanz des entsprechenden Type-Objekts verwendet hat, muss statt Null übergeben werden. Es könnte auch eine ähnliche Lösung geben. – SergGr

+0

Vielen Dank sir :-) – stiank81

Antwort

7

an der Quelle der Suche (und der Stack-Trace I von reproing haben, die Sie nicht angegeben: P)

Dies liegt daran, es auf eine andere Überlastung des ConstructorArgument Ctor als die normale Nutzung (dh wo es ist verbindlich Übergeben eines Werttyps oder eines Nicht-Null-Referenztyps).

Die Abhilfe ist die Null zu gieße Objekt -

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

Ninject 2 Quelle:

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)); 
    } 
} 

Lektion? Du wärst verrückt, die neueste Quelle nicht herunterzuladen und anzuschauen. Tolle Kommentare, schöne, saubere Codebasis. Nochmals vielen Dank an @Ian Davis für diesen Tipp!

+0

+1 Schön - interessante Sachen. – Finglas

+0

Thx für die Erklärung. Ich glaube nicht, dass ich Nullen in Objekte umwandeln möchte, aber das scheint meine Frage zu beantworten! Vielleicht muss ich mir die neueste Quelle ansehen :-) – stiank81

+0

@ stiank81: Wie mein Kommentar zu @Finglas 'Antwort (die ich glaube, ist die richtige Antwort, auch wenn ich zustimme, sollte das Akzeptierte sein: P), der Grund ist hässlich ist, weil es nicht beabsichtigt ist, in normalem Gebrauch gemacht zu werden (deckten wir nicht, dass ConstructorArgument eine schlechte Standardannäherung in einer anderen Frage ist?) @Finglas: Dank und Dank für das Entfernen der anderen Sachen –

0

Dies ist wahrscheinlich nicht unterstützt wird, weil Konstruktorargumente zu Werttypen sein kann.

+0

Dies veranlasste mich, die richtige Antwort zu finden, weil es sich falsch anfühlte. Aber es veranlasste mich auch im Nachhinein dazu, Brians Antwort nicht zuzustimmen (ich ließ beide +0 als zu spät, um die andere rückgängig zu machen und während beide konzeptionelle Einblicke lieferten, glaube ich nicht, dass sie etwas darstellen, was Ninject zu ermutigen/verhindert/force) –

3

Ich kenne Ninject nicht, aber AFAIK-Konstruktor-Injektion wird häufig für obligatorische Abhängigkeiten verwendet und daher macht Null in diesem Zusammenhang wenig Sinn. Wenn die Abhängigkeit nicht obligatorisch ist, sollte der Typ einen Standardkonstruktor bereitstellen und stattdessen die Eigenschaft injection verwenden.

This post bietet zusätzliche Informationen.

+0

I + 1d dies, weil es logischer schien als Gerries Antwort.Bei der Reflektion stimme ich allerdings nicht wirklich zu, da es sowohl für Value-Typen als auch für Reference-Typen verwendet werden kann und der Punkt in diesem Zusammenhang nicht wirklich verallgemeinert wird. Worauf man sich schützen möchte, ist nicht spezifiziert, zufällig nicht initialisiert und/oder Abhängigkeiten, die nicht eindeutig spezifiziert sind, dass Tools Ihnen helfen können, Abhängigkeiten mit zu identifizieren. –

+0

Property-Injektion ist eine akzeptable Lösung dafür? Wenn dem so ist, klingt das nach einer vernünftigen Sache. Danke für die Verbindung. – stiank81

+0

@ stiank81: Während Property Injection die grundlegende Sache erreichen kann, die Sie versuchen zu erreichen (viele 'Null'-Werte), werden Sie dadurch viel Code Cleanliness verlieren, also würde ich nein - I sagen verweisen Sie auf die Antwort von @ Finglas. –

3

Ich möchte es in meiner Einheit verwenden, prüft

Es no need to use an IOC container for unit tests ist. Sie sollten den Container verwenden, um Ihre Anwendung zur Laufzeit miteinander zu verbinden, und nicht mehr. Und wenn das zu schaden beginnt, es ist ein Geruch Klasse angibt aus der Hand

Ihr Gerät zu testen würde dann in diesem Beispiel sein (SRP Verletzung?):

var ninja = new Ninja(null); 

Das oben ist echt C# -Code und das Übergeben einer Nullreferenz für Komponententests ist eine vollkommen gültige Methode zum Testen von Bereichen, in denen die Abhängigkeit nicht erforderlich ist.

+0

+1 wichtiger Punkt, selbst wenn es nicht antwortet die Frage (obwohl die Tatsache, dass dies der Fall ist, ist wahrscheinlich, warum dieses Problem (Auflösung zu falsch Überladung im Falle von "Null") wurde nicht als ein Problem betrachtet. –

+0

@ Ruben: Das ist gut, neben dem ist, was SO ist alles über Verbessern und lernen. – Finglas