2012-06-11 40 views
9

Actualización: ¿Hay alguna manera de lograr lo que estoy tratando de hacer en un framework IoC distinto de Windsor? Windsor manejará bien los controladores, pero no resolverá nada más. Estoy seguro de que es mi culpa, pero sigo el tutorial textualmente y los objetos no se resuelven con la inyección de ctor, siguen siendo nulos a pesar de hacer los registros y resolverlos. Desde entonces, he descartado mi código DI y tengo la inyección manual por ahora porque el proyecto es sensible al tiempo. Esperando obtener DI resuelto antes de la fecha límite.Inyección de dependencia con la interfaz implementada por varias clases


tengo una solución que tiene varias clases que todos implementan la misma interfaz

Como un simple ejemplo, los Interface

public interface IMyInterface { 
    string GetString(); 
    int GetInt(); 
    ... 
} 

Las clases concretas

public class MyClassOne : IMyInterface { 
    public string GetString() { 
     .... 
    } 
    public int GetInt() { 
     .... 
    } 
} 

public class MyClassTwo : IMyInterface { 
    public string GetString() { 
     .... 
    } 
    public int GetInt() { 
     .... 
    } 
} 

Ahora estas clases se inyectarán donde sea necesario en capas superiores a ellas como:

public class HomeController { 

    private readonly IMyInterface myInterface; 

    public HomeController() {} 

    public HomeController(IMyInterface _myInterface) { 
     myInterface = _myInterface 
    } 
    ... 
} 

public class OtherController { 

    private readonly IMyInterface myInterface; 

    public OtherController() {} 

    public OtherController(IMyInterface _myInterface) { 
     myInterface = _myInterface 
    } 
    ... 
} 

Ambos controladores se inyectan con la misma interfaz.

Cuando se trata de resolver estas interfaces con la clase concreta adecuada en mi COI, ¿cómo puedo diferenciar HomeController que necesita una instancia de MyClassOne y OtherController necesita una instancia de MyClassTwo?

¿Cómo puedo vincular dos clases concretas diferentes a la misma interfaz en el IoC? No quiero crear 2 interfaces diferentes ya que eso rompe la regla DRY y no tiene sentido de todos modos.

En el castillo de Windsor Me gustaría tener 2 líneas de este tipo:

container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>()); 
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>()); 

Esto no va a funcionar porque yo sólo alguna vez obtener una copia de MyClassTwo porque es el último registrado para la interfaz.

Como dije, no entiendo cómo puedo hacerlo sin crear interfaces específicas para cada concreto, haciendo eso no solo rompe las reglas DRY sino también el OOP básico. ¿Cómo logro esto?


Actualización basada en la respuesta de Mark Polsen


Aquí está mi actual COI, donde irían los .Resolve declaraciones? Yo no ver nada en la documentación Windsor

public class Dependency : IDependency { 

    private readonly WindsorContainer container = new WindsorContainer(); 

    private IDependency() { 
    } 

    public IDependency AddWeb() { 
     ... 

     container.Register(Component.For<IListItemRepository>().ImplementedBy<ProgramTypeRepository>().Named("ProgramTypeList")); 
     container.Register(Component.For<IListItemRepository>().ImplementedBy<IndexTypeRepository>().Named("IndexTypeList")); 

     return this; 
    } 

    public static IDependency Start() { 
     return new IDependency(); 
    } 
} 
+0

Usted puede unirse directamente a las clases concretas si es necesario. (bueno, al menos con Ninject puedes, pero no puedo imaginar que no puedas hacerlo con otras inmersiones.) – Buildstarted

+0

No quieres hacer eso. Las dependencias de tus clases son ambiguas. No puede simplemente mirar una de las clases y decir que necesita una implementación específica. Recomiendo que use una fábrica como dependencia en ambas clases. Lea más aquí: http://www.codeproject.com/Articles/386164/Get-injected-into-the-world-of-inverted-dependenci – jgauffin

+0

@jgauffin La promesa del método '.Named (...)' de Windsor es que puede resolver esa ambigüedad, pero en el uso real, no puedo hacer que Windsor resuelva nada :-( –

Respuesta

5

Debería poder realizarlo con el registro de componente con nombre.

container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassOne>().Named("One")); 
container.Register(Component.For<IMyInterface>().ImplementedBy<MyClassTwo>().Named("Two")); 

y luego a resolver con

kernel.Resolve<IMyInterface>("One"); 

o

kernel.Resolve<IMyInterface>("Two"); 

See: To specify a name for the component

+0

¡Esto parece prometedor! –

+0

Estoy trabajando fuera de una aplicación de muestra que usa Castle Windsor, usa las líneas 'container.Register (...' pero no usa 'container.Resolve ...' en ningún lado. ¿Hay un lugar específico? que 'container.Resolve ...' va o justo después de '.Register'? –

+0

Lo siento, en lugar de contenedor, debería ser kernel, donde kernal es tipo IKernel. –

7

espero que puedan utilizar service overrides.

Ej.

container.Register(
    Component.For<IMyService>() 
     .ImplementedBy<MyServiceImpl>() 
     .Named("myservice.default"), 
    Component.For<IMyService>() 
     .ImplementedBy<OtherServiceImpl>() 
     .Named("myservice.alternative"), 

    Component.For<ProductController>() 
     .ServiceOverrides(ServiceOverride.ForKey("myService").Eq("myservice.alternative")) 
); 

public class ProductController 
{ 
    // Will get a OtherServiceImpl for myService. 
    // MyServiceImpl would be given without the service override. 
    public ProductController(IMyService myService) 
    { 
    } 
} 
+0

¡Esto también parece prometedor! –

+0

Éste no funciona para mí ya que mi IoC no está en la capa de interfaz de usuario MVC, así que no puedo usar 'Component.For () 'como desearía d tiene que hacer referencia al conjunto de UI y eso causará una referencia circular. –

2

Típicamente contenedores DI siguen Registro, la resolución y la liberación de patrones. Durante la fase de registro hay dos pasos. El primero es especificar la asignación como lo está haciendo. El segundo paso es especificar las reglas que regulan a qué inyectar dónde.

Este problema es muy común cuando tratamos de resolver problemas de corte transversal utilizando decoradores. En estas situaciones, tiene múltiples clases (decoradores) que implementan una única interfaz.

En pocas palabras, tenemos que implementar IModelInterceptorsSelector, que le permite escribir un código imperativo que decide qué Interceptor debe aplicar a qué tipos o miembros.

Esto se describe detalladamente en el libro Dependency Injection en el libro .NET de Mark Seemann. Busque la interceptación del capítulo 9 o busque la interfaz anterior.

No soy un experto en esto, pero estaba buscando exactamente el mismo problema y encontré las ans en el libro anterior.

Espero que esto ayude.

Saludos Dev1

Cuestiones relacionadas