2010-02-09 8 views
61

Decidí comenzar a usar Ninject y enfrentar un problema. Digamos que tengo el siguiente escenario. Tengo una interfaz IService y 2 clases que implementan esta interfaz. Y también tengo una clase, que tiene un constructor que obtiene IService y un int. ¿Cómo puedo crear una instancia de esta clase con Ninject (no quiero conectar esta int, quiero pasarla cada vez que obtengo una instancia)?Crear una instancia usando Ninject con parámetros adicionales en el constructor

Aquí hay un código que ilustra la situación:

interface IService 
{ 
    void Func(); 
} 

class StandardService : IService 
{ 
    public void Func() 
    { 
     Console.WriteLine("Standard"); 
    } 
} 

class AlternativeService : IService 
{ 
    public void Func() 
    { 
     Console.WriteLine("Alternative"); 
    } 
} 


class MyClass 
{ 
    public MyClass(IService service, int i) 
    { 
     this.service = service; 
    } 

    public void Func() 
    { 
     service.Func(); 
    } 

    IService service = null; 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     IKernel kernel = new StandardKernel(new InlineModule(
      x => x.Bind<IService>().To<AlternativeService>(), 
      x => x.Bind<MyClass>().ToSelf())); 

     IService service = kernel.Get<IService>(); 

     MyClass m = kernel.Get<MyClass>(); 
     m.Func(); 
    } 
} 

Respuesta

84

El With.ConstructorArgument existía en 1,0 para este propósito. En la versión 2.0, la sintaxis ha cambiado ligeramente: - With.Parameters.ConstructorArgument with ninject 2.0

Ver Inject value into injected dependency para más detalles y ejemplos de cómo usar el contexto, los proveedores y los argumentos para transmitir cosas como esta todo más correctamente.

EDIT: Como Steven ha elegido para fingir mi comentario es irrelevante, estaría mejor dejar en claro lo que quiero decir con algunos ejemplos (de 2.0):

MyClass m = kernel.Get<MyClass>(new ConstructorArgument("i", 2)); 

la que a mis ojos es muy clara y declara exactamente lo que está sucediendo.

Si estás en una posición donde se puede determinar el parámetro de una manera más global puede registrar un proveedor y hacerlo de esta manera:

class MyClassProvider : SimpleProvider<MyClass> 
{ 
    protected override MyClass CreateInstance(IContext context) 
    { 
     return new MyClass(context.Kernel.Get<IService>(), CalculateINow()); 
    } 
} 

y registrarlo como esto:

x => x.Bind<MyClass>().ToProvider(new MyClassProvider()) 

NB el bit CalculateINow() es donde pondría su lógica como en la primera respuesta.

O hacerlo más complejo como esto:

class MyClassProviderCustom : SimpleProvider<MyClass> 
{ 
    readonly Func<int> _calculateINow; 
    public MyClassProviderCustom(Func<int> calculateINow) 
    { 
     _calculateINow = calculateINow; 
    } 

    protected override MyClass CreateInstance(IContext context) 
    { 
     return new MyClass(context.Kernel.Get<IService>(), _calculateINow()); 
    } 
} 

la que desee registrar de esta manera:

x => x.Bind<MyClass>().ToProvider(new MyClassProviderCustom(() => new Random().Next(9))) 

ACTUALIZACIÓN: reciente mecanismos que exhiben patrones mucho mejores con menos repetitivo de los anteriores son encarnado en la extensión Ninject.Extensions.Factory, consulte: https://github.com/ninject/ninject.extensions.factory/wiki

Como se dijo anteriormente, if you need to pass a different parameter each time and you have multiple levels in the dependency graph, you might need to do something like this.

Una consideración final es que debido a que no se ha especificado un Using<Behavior>, que va por defecto al valor por defecto como se especifica/incumplido en las opciones para el kernel (TransientBehavior en la muestra), que podría hacer que la fábrica calcula i sobre la marcha discutible [por ejemplo, si el objeto estaba en la memoria caché]

Ahora, para aclarar algunos otros puntos en los comentarios que se están FUD y se pasan por alto. Algunas cosas importantes a tener en cuenta sobre el uso de DI, ya sea Ninject o cualquier otra cosa es:

  1. tener tanto como sea posible realizado por inyección de constructor de modo que usted no necesita utilizar atributos y trucos específicos de contenedores.Hay una buena publicación en el blog llamada Your IoC Container is Showing.

  2. Minimice el código que va al contenedor y solicite cosas; de lo contrario, su código se combina con a) el contenedor específico (que el CSL puede minimizar) b) la forma en que se distribuye todo el proyecto. Hay buenas publicaciones de blog que muestran que CSL no está haciendo lo que crees que hace. Este tema general se conoce como Service Location vs Dependency Injection. ACTUALIZACIÓN: Consulte http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx para obtener una explicación detallada y completa.

  3. Minimizar el uso de la estática y simple

  4. No asuma que sólo hay un contenedor [global] y que está bien que simplemente exigir que siempre que lo necesite como un buen variable global. El uso correcto de varios módulos y Bind.ToProvider() le da una estructura para gestionar esto. De esta manera cada subsistema por separado puede trabajar por su cuenta y usted no tendrá componentes de bajo nivel están vinculados a los componentes de primer nivel, etc.

Si alguien quiere rellenar los enlaces a los blogs que me refiero a, agradecería que (todos ya están vinculados desde otras publicaciones en SO, así que todo esto es solo una duplicación que he introducido con el objetivo de evitar la confusión de una respuesta engañosa.)

Ahora , ¡si tan solo Joel pudiera entrar y realmente me aclarase la sintaxis agradable y/o la forma correcta de hacerlo!

ACTUALIZACIÓN: Si bien esta respuesta es claramente útil a partir del número de upvotes que ha cosechado, me gustaría hacer las siguientes recomendaciones:

  • Lo anterior se siente como que es un poco anticuado, y para ser honesto refleja una Mucho pensamiento incompleto que casi parece embarazoso desde la lectura Dependency Injection in .net - Correr y comprarlo ahora - no se trata solo de DI, la primera mitad es un tratamiento completo de todas las preocupaciones de la arquitectura que lo rodea de un hombre que ha pasado demasiado tiempo aquí colgando alrededor de la etiqueta de inyección de dependencia.
  • ir a leer Mark Seemann's top rated posts here on SO right now - usted aprenderá valiosas técnicas de cada uno
+0

bueno encontrar esto, ya que la documentación es tan atrás .... – Elton

Cuestiones relacionadas