2012-10-29 2 views
12

Ho un'interfaccia: IFoo
Due classi che implementano tale interfaccia: FooOne e FooTwo
E due classi ClassOne e ClassTwo ricevono un parametro IFoo nel costruttore.Unity - Iniettare classi diverse per la stessa interfaccia

Come posso configurare l'unità in modo ClassOne riceve un'istanza FooOne e ClassTwo riceve un FooTwo utilizzando un solo contenitore?

Non riesco a farlo in fase di esecuzione, quindi deve essere nel file di configurazione.

risposta

3

È necessario dare loro i nomi di registrazione per farlo:

// Create an instance of a service you want to use. Alternatively, this 
// may have been created by another process and passed to your application 
LoggingService myLoggingService = new LoggingService(); 

// Register the existing object instance with the container 
container.RegisterInstance<IMyService>("Logging", myLoggingService); 

// Register a mapping for another service your application will use 
container.RegisterType<IMyService, myDataService>("DataService"); 

// When required, retrieve an instance of these services 
IMyService theDataService = container.Resolve<IMyService>("DataService"); 
IMyService theLoggingService = container.Resolve<IMyService>("Logging"); 

Tratto da Resolving Instances Of Types Using Unity

+0

Nella mia applicazione, abbiamo predefinita implementazione dell'interfaccia e che sia registrato con Unity. Ma i consumatori sono liberi di avere la propria implementazione e registrarla usando 'app.config'. Puoi dire come gestire questo caso? Come garantire che venga utilizzato quello non predefinito se uno di questi tipi viene registrato? – Learner

+0

Controlla la risposta di @SebastianWeber per i dettagli sull'utilizzo dei file di configurazione per registrare i tuoi servizi. – Fenton

+0

Grazie per la risposta. Ma quella risposta non mi è utile.Perché voglio assicurarmi che l'istanza predefinita registrata con Unity sia "non registrata" e che sia sempre fornita quella configurata dall'utente. – Learner

18

Dai un'occhiata al Unity documentation.

Per un file di configurazione più leggibile si dovrebbe definire il tipo di alias per IFoo, FooOne, FooTwo, ClassOne e ClassTwo. Quindi è necessario registrare i mapping da IFoo alle implementazioni. È necessario impostare un name per i mapping. Per i consumatori di IFoo è necessario registrare uno InjectionConstructor.

propria configurazione sarà simile a questo:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <configSections> 
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, 
     Microsoft.Practices.Unity.Configuration"/> 
    </configSections> 
    <unity xmlns="http://schemas.microsoft.com/practices/2010/unity"> 
    <alias alias="IFoo" type="UnityConfigFile.IFoo, UnityConfigFile" /> 
    <alias alias="FooOne" type="UnityConfigFile.FooOne, UnityConfigFile" /> 
    <alias alias="FooTwo" type="UnityConfigFile.FooTwo, UnityConfigFile" /> 
    <alias alias="ClassOne" type="UnityConfigFile.ClassOne, UnityConfigFile" /> 
    <alias alias="ClassTwo" type="UnityConfigFile.ClassTwo, UnityConfigFile" /> 
    <container> 
     <register type="IFoo" name="1" mapTo="FooOne" /> 
     <register type="IFoo" name="2" mapTo="FooTwo" /> 
     <register type="ClassOne" mapTo="ClassOne"> 
     <constructor> 
      <param name="foo"> 
      <dependency type="IFoo" name="1" /> 
      </param> 
     </constructor> 
     </register> 
     <register type="ClassTwo" mapTo="ClassTwo"> 
     <constructor> 
      <param name="foo"> 
      <dependency type="IFoo" name="2" /> 
      </param> 
     </constructor> 
     </register> 
    </container> 
    </unity> 
</configuration> 

Questo è il prova corrispondente che mostra come funziona.

UnityConfigurationSection config = 
    (UnityConfigurationSection) ConfigurationManager.GetSection("unity"); 
IUnityContainer container = new UnityContainer(); 
container.LoadConfiguration(config); 
ClassTwo two = container.Resolve<ClassTwo>(); 
Assert.IsInstanceOfType(two.Foo, typeof(FooTwo)); 

Aggiornamento

In fase di esecuzione si può fare in questo modo

IUnityContainer container = new UnityContainer(); 
container.RegisterType<IFoo, FooOne>("One"); 
container.RegisterType<IFoo, FooTwo>("Two"); 
container.RegisterType<ClassOne>(new InjectionConstructor(
    new ResolvedParameter<IFoo>("One"))); 
container.RegisterType<ClassTwo>(new InjectionConstructor(
    new ResolvedParameter<IFoo>("Two"))); 
+0

Come lo faresti in fase di runtime? – Kurren

+3

@Kurren vedere il mio aggiornamento –

0

ho configurato nella mia domanda come questa

Nuget pacchetto Unità installata la versione 4.0. 1

<package id="Unity" version="4.0.1" targetFramework="net452" /> 

Nel mio App.config

<configSections> 
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration" /> 
</configSections> 

<unity> 
    <container> 
     <register type="MyApp.MainWindow, MyApp"> 
      <lifetime type="singleton" /> 
     </register> 
     <register name="UnityResolver" type="MyApp.Core.Interface.IResolver, MyApp.Core.Interface" mapTo="Avelyn.Core.Container.UnityResolver, Avelyn.Core" /> 
     <register name="NinjectResolver" type="MyApp.Core.Interface.IResolver, MyApp.Core.Interface" mapTo="Avelyn.Core.Container.NinjectResolver, Avelyn.Core" /> 
    </container> 
</unity> 

In My App.xaml.cs

var _container = new UnityContainer(); 
_container.LoadConfiguration(); 

IResolver _unityResolver = _container.Resolve<IResolver>("UnityResolver"); 
IResolver _ninject = _container.Resolve<IResolver>("NinjectResolver"); 
MainWindow _win = _container.Resolve<MainWindow>();