2012-03-22 11 views
5

Ho il seguente codice:Come registrare una classe che ha `Func <>` come parametro?

_container = new UnityContainer(); 
_container.RegisterType<IDownloader, Downloader>(); 
_container.RegisterType<INewObject, NewObject>(); 
_container.RegisterType<SearchViewModel>(); 

SearchViewModel classe con l'iniezione del costruttore:

class SearchViewModel 
{ 
    private readonly Func<IDownloader> _downloaderFactory; 
    private readonly INewObject _newObject; 
    private IDownloader _downloader; 

    public SearchViewModel(Func<IDownloader> downloaderFactory, INewObject newObject) 
    { 
     _downloaderFactory = downloaderFactory; 
     _newObject = newObject; 
    }   
} 

La domanda: Come registrareSearchViewModel che ha Fun<> come parametro?

_container.RegisterType<SearchViewModel>(new InjectionConstructor(DownloaderFactory())); 

Il codice di cui sopra funziona solo senza INewObject.

L'obiettivo: fabbrica Resolve con InjectionConstructor e risolvere INewObject, INewObject2, INewObject3 automaticamente (come senza parametri: RegisterType<SearchViewModel>()).

È possibile? Forse si alterna?

+1

Perché non si utilizza l'iniezione di Setter per i parametri INewObject? – daryal

+0

Perché rendere SearchViewModel dipendente da Func ? Non è l'astrazione che perde? Penso che dovresti inserire direttamente l'interfaccia di IDownloader. L'implementazione concreta di IDownloader può incapsulare il comportamento di fabbrica. Guarda l'esempio del codice qui: http://stackoverflow.com/questions/9757953/can-any-of-existing-ioc-containers-create-the-lazy-proxy-classes-dynamically –

risposta

8

ho risolto il problema:

_container.RegisterType<Func<IDownloader>>(new InjectionFactory(i => 
      new Func<IDownloader> (() => _container.Resolve<IDownloader>()))); 
_container.RegisterType<SearchViewModel>(); 

nuovo Func è una chiave, perché prima provato:

_container.RegisterType<Func<IDownloader>>(new InjectionFactory(i => 
      _container.Resolve<IDownloader>())); 

Anche il modo migliore per utilizzare IDownloaderFactory anziché Func<IDownloader> downloaderFactory. IDownloaderFactory può incapsulare il delegato.

Inoltre, penso che l'utilizzo di un delegato come dipendenza all'interno della fabbrica sia una soluzione migliore rispetto a Broken Root di composizione.

2

Il modello generalmente accettato da usare qui è per dichiarare una fabbrica di astratto e renderlo un po 'più esplicito:

public interface IDownloaderFactory 
{ 
    IDownloader Create(); 
} 

Poi si crea una classe per rappresentare la fabbrica che usa semplicemente il contenitore di nuovo per risolvere i casi:

public class DownloaderFactory : IDownloaderFactory 
{ 
    private UnityContainer _Container; 
    public DownloaderFactory(UnityContainer container) 
    { 
     this._Container = container; 
    } 

    public IDownloader Create() 
    { 
     return this._Container.Resolve<IDownloader>(); 
    } 
} 

Usando questo approccio è più esplicito e più gioca bene con i contenitori, anche conserva ancora il contenitore lontano dalla vostra applicazione e la logica di business, ora è sufficiente un piccolo aggiustamento alla classe SearchViewModel:

class SearchViewModel 
{ 
    private readonly IDownloaderFactory _downloaderFactory; 
    private readonly INewObject _newObject; 

    public SearchViewModel(IDownloaderFactory downloaderFactory, INewObject newObject) 
    { 
     _downloaderFactory = downloaderFactory; 
     _newObject = newObject; 

     Console.WriteLine(downloaderFactory.Create().GetHashCode()); 
     Console.WriteLine(downloaderFactory.Create().GetHashCode()); 
    } 

}

Ora si può vedere solo funziona e crea nuove istanze di volta in volta.

Impostazione del contenitore sarebbe simile a questa:

 var container = new UnityContainer(); 
     container.RegisterType<IDownloader, Downloader>(); 
     container.RegisterType<INewObject, NewObject>(); 
     container.RegisterType<IDownloaderFactory, DownloaderFactory>(); 
     container.RegisterType<SearchViewModel>(); 
     container.RegisterInstance(container); 
     var model = container.Resolve<SearchViewModel>(); 

Si noti che è necessario registrare l'istanza del contenitore si sta lavorando in modo che la fabbrica ottiene la stessa istanza sia con questo metodo o un ThreadLocal istanzia o qualcosa.

Nota: anche essere solo diffidenti nei confronti del fatto che utilizzando l'approccio Func o utilizzando il contenitore per risolvere il downloader può causare effetti indesiderati nel tuo client. Ad esempio, se il contenitore è impostato di default come transitorio per gli oggetti di Downloader, ogni volta viene creata una nuova istanza. Cambiando la durata del contenitore, il client può ottenere ogni volta la stessa istanza. In tal caso è meglio costruire manualmente l'oggetto downloader in fabbrica e utilizzare il contenitore solo per gli argomenti del downloader.

Problemi correlati