2012-06-11 14 views
9

Aggiornamento: C'è un modo per ottenere ciò che sto cercando di fare in un framework IoC diverso da Windsor? Windsor gestirà bene i controller ma non risolverà nient'altro. Sono sicuro che sia colpa mia, ma sto seguendo il tutorial verbatim e gli oggetti non si risolvono con l'iniezione di ctor, sono ancora nulli nonostante i registri e le risoluzioni. Da allora ho scartato il mio codice DI e ho fatto un'iniezione manuale perché il progetto è sensibile al fattore tempo. Sperando di ottenere che DI abbia funzionato prima della scadenza.Iniezione di dipendenza con interfaccia implementata da più classi


Ho una soluzione che dispone di più classi che tutto implementano la stessa interfaccia

Come semplice esempio, i Interface

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

Le classi concrete

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

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

Ora queste classi saranno iniettate dove necessario in strati sopra di loro come:

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 
    } 
    ... 
} 

Entrambi i controller vengono iniettati con la stessa interfaccia.

Quando si tratta di risolvere queste interfacce con la classe concreta corretta nel mio CIO, come faccio a differenziare che HomeController ha bisogno di un'istanza di MyClassOne e OtherController ha bisogno di un'istanza di MyClassTwo?

Come si collegano due diverse classi concrete alla stessa interfaccia in IoC? Non voglio creare 2 interfacce diverse in quanto interrompe la regola DRY e non ha comunque senso.

Nel Castello di Windsor avrei 2 righe come questo:

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

Questo non funzionerà perché sarò sempre e solo ottenere una copia di MyClassTwo perché è l'ultimo registrato per l'interfaccia.

Come ho detto, non capisco come posso farlo senza creare interfacce specifiche per ogni concreto, facendo che si rompono non solo le regole ASCIUTATE ma anche l'OOP di base. Come ottengo questo?


Aggiornamento in base alla risposta di Mark Polsen


ecco la mia attuale CIO, dove sarebbe il .Resolve dichiarazioni vanno? I don' vedere nulla nella documentazione 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

è possibile associare direttamente alle classi concrete, se necessario. (beh, almeno con Ninject puoi farlo ma non riesco a immaginare che non puoi farlo con altri cali.) – Buildstarted

+0

Non vuoi farlo. Le dipendenze delle tue classi sono ambigue. Non puoi semplicemente guardare una delle classi e dire che ha bisogno di un'implementazione specifica. Raccomando di utilizzare una factory come dipendenza in entrambe le classi. Leggi di più qui: http://www.codeproject.com/Articles/386164/Get-injected-into-the-world-of-inverted-dependenci – jgauffin

+0

@jgauffin La promessa del metodo '.Named (...) di Windsor è che può risolvere quell'ambiguità, ma nell'uso effettivo, non posso convincere Windsor a risolvere nulla :-( –

risposta

5

Si dovrebbe essere in grado di farlo con la registrazione del componente denominato.

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

e poi risolvere con

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

o

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

See: To specify a name for the component

+0

Questo sembra promettente! –

+0

Sto lavorando su un'app di esempio che utilizza Castle Windsor, usa le righe 'container.Register (...' ma non usa alcun 'contenitore.Risolve ... 'ovunque. C'è un posto specifico quel 'container.Resolve ...' va o proprio lì dopo '.Register'? –

+0

Scusa, invece del contenitore, dovrebbe essere il kernel, dove kernal è il tipo IKernel. –

7

Spero che è possibile utilizzare service overrides.

Es.

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

Anche questo sembra molto promettente! –

+0

Questo non funziona per me dato che il mio IoC non è nel livello UI MVC quindi non posso usare 'Component.For () 'come vorrei D deve fare riferimento al gruppo UI e ciò causerà un riferimento circolare. –

2

Tipicamente contenitori DI seguire Register, risolutezza e Rilasciare modelli. Durante la fase di registrazione ci sono due passaggi. Il primo è specificare la mappatura come si sta facendo. Il secondo passo è specificare le regole che governano quali iniettare dove.

Questo problema è molto comune quando si tenta di risolvere i problemi di taglio trasversale utilizzando decoratori. In queste situazioni, hai più classi (decoratori) che implementano una singola interfaccia.

In breve, è necessario implementare IModelInterceptorsSelector che consente di scrivere codice imperativo che decide quale Interceptor applicare a quali tipi o membri.

Questo è descritto dettagliatamente nel libro Dependency Injection in .Net book di Mark Seemann. Cerca intercettazione capitolo 9 o cerca l'interfaccia di cui sopra.

Non sono un esperto in questo, ma cercavo lo stesso identico problema e ho trovato le ans nel libro sopra.

Spero che questo aiuti.

saluti Dev1