2011-07-01 13 views
19

Tengo indicadores globales que habilitan/deshabilitan características. Me gustaría inyectar algunas dependencias dependiendo de alguna bandera. Algunas características requieren clases que están muy construidas, por lo que quiero inyectar nulo si el valor del indicador es falso y la dependencia real de lo contrario. Ninject no permite inyectar nulo. ¿Hay más opciones?Ninject. Inyección opcional

Actualización: los argumentos del constructor se pueden decorar con el atributo OptionalAttribute. En este caso, nulo se inyecta si no se encuentra el enlace correspondiente. Aquí hay un problema: no puedo verificar si la clase objetivo puede construirse correctamente. Tengo una prueba para cada dependencia pública que verifica si se puede construir con éxito. En caso de que el valor de la bandera sea verdadero, no podré encontrar el error cuando la dependencia decorada con el atributo OptionalAttribute no se pueda construir correctamente. Me gustaría gestionarlo solo en el nivel de enlace.

Respuesta

17

Puede variar el comportamiento de inyección vinculándose mediante un método de fábrica (es decir, ToMethod), y es posible permitir la inyección de valores nulos configurando la configuración del contenedor AllowNullInjection.

Otra alternativa sería utilizar un método de fábrica y suministrar un objeto simulado liviano en lugar de su clase pesada. Si está utilizando interfaces esto sería sencillo, solo tiene implementaciones de la interfaz que no hacen nada. Incluso podría usar un marco burlón como FakeItEasy para construir estos dummies para usted. La ventaja aquí es que el maniquí hace que el comportamiento especial transparente para los clientes es decir, los clientes no tienen que comprobar si hay null, etc.

Un ejemplo del uso de un método de fábrica, además de AllowNullInjection y nulos:

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

Y un ejemplo en el que se sustituye un objeto ligero dependiendo de la bandera:

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

inyección nula por lo general no es una buena idea. Esto contamina el código con comprueba si el objeto es nulo o no como lo muestra el siguiente código:

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 mejor forma en este caso es la implementación de un objeto nulo, que no hace absolutamente nada y se inyecta éste en lugar de nulo. Esto mantiene tu código limpio.

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(); 
    } 
} 
Cuestiones relacionadas