2010-04-19 14 views
5

Al usar Ninjects ConstructorArgument puede especificar el valor exacto para inyectar a parámetros específicos. ¿Por qué este valor no puede ser nulo o cómo puedo hacerlo funcionar? Tal vez no es algo que le gustaría hacer, pero quiero utilizarlo en mis pruebas de unidad .. Ejemplo:¿Por qué no puedo inyectar valor nulo con 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

No estoy familiarizado con ninject, pero creo que el problema es que IoC-container utiliza información de tipo para encontrar un constructor adecuado y no puede encontrarlo por valor nulo. Será mejor que busque una respuesta en la documentación o en su código. En una biblioteca que utilicé se debe pasar la instancia del objeto Type correspondiente en lugar de null. Puede haber alguna solución similar aquí también. – SergGr

+0

Gracias, señor :-) – stiank81

Respuesta

7

En cuanto a la fuente (y el seguimiento de la pila llegué por reproing la que se omitiera: P)

Esto se debe a que es la unión a una sobrecarga diferente de la ctor ConstructorArgument que el uso normal (es decir, donde' re pasando un tipo de valor o un tipo de referencia no nulo).

La solución consiste en emitir la hipótesis nula a Objeto: -

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

Ninject 2 Fuente:

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

lección? Estaría loco no descargar la última fuente y mirarla. Grandes comentarios, buena base de código limpia. ¡Gracias de nuevo a @Ian Davis por ese consejo/consejo!

+0

+1 Bonito - cosas interesantes. – Finglas

+0

Thx para la explicación. Sin embargo, no creo que quiera andar lanzando nulos a los objetos, ¡pero esto parece responder a mi pregunta! Tal vez tengo que ver la última fuente :-) – stiank81

+0

@ stiank81: Como mi comentario sobre la respuesta de @Finglas (que creo que es la respuesta correcta, incluso si estoy de acuerdo con esto debe ser El Aceptado: P) dice, la razón por la que es feo es porque no está destinado a ser hecho en el uso normal (¿No cubrimos ConstructorArgument siendo un mal enfoque por defecto en otra pregunta? P) @Finglas: Gracias, y gracias por quitar las otras cosas –

0

Esto es probablemente porque no soportado argumentos de constructor pueden ser los tipos de valor también.

+0

Esto me llevó a encontrar la respuesta real, ya que se sentía mal. Pero también me impulsó a reflexionar para estar en desacuerdo con la respuesta de Brian (dejaría ambas +0 como demasiado tarde para deshacer la otra y, aunque ambas proporcionaron información conceptual, no creo que representen nada que Ninject intente alentar/prevenir/fuerza) –

3

No sé Ninject, pero la inyección del constructor AFAIK se usa comúnmente para las dependencias obligatorias y, por lo tanto, nulo tiene poco sentido en este contexto. Si la dependencia no es obligatoria, el tipo debe proporcionar un constructor predeterminado y usar la inyección de propiedad en su lugar.

This post proporciona información adicional.

+0

I + 1d esto porque parecía más lógico que la respuesta de Gerrie.Reflexionando, no estoy de acuerdo, ya que se puede usar tanto para Tipos de valores como para Tipos de referencia, y el punto no se generaliza bien en ese contexto. Lo que se quiere proteger es no especificado, no inicializado aleatoriamente y/o dependencias que no están especificadas de una manera clara que las herramientas pueden ayudarlo a identificar las cadenas de dependencia. –

+0

¿La inyección de propiedad es una solución aceptable para esto? Si es así, esto parece razonable. Thx para el enlace. – stiank81

+0

@ stiank81: Si bien la inyección de propiedades puede lograr lo básico que estás tratando de lograr (muchos valores 'nulos'), al hacerlo te perderá mucho en Code Cleanliness, así que diría que no - I referirlo a la respuesta de @Finglas. –

3

quiero usarlo en mi equipo realiza un test

Hay no need to use an IOC container for unit tests. Debe usar el contenedor para conectar su aplicación en conjunto en el tiempo de ejecución, y nada más. Y si eso empieza a doler, es un olor que indica que su clase está yendo de las manos

Su prueba de la unidad estaría entonces en este ejemplo (violación de SRP?):

var ninja = new Ninja(null); 

Lo anterior es de fiar código C# , y pasar una referencia nula para pruebas unitarias es una forma perfectamente válida de áreas de pruebas unitarias que no necesitan la dependencia.

+0

+1 Punto importante incluso si no responde la pregunta (aunque el hecho de que este sea el caso es probablemente la razón por la cual este problema (resolver sobrecarga errónea en caso de 'null') no se ha considerado un problema. –

+0

@Ruben: Está bien, además de eso es de lo que se trata SO . Mejorando y aprendiendo. – Finglas

Cuestiones relacionadas