2012-03-22 17 views
5

tengo el siguiente código:¿Cómo registrar una clase que tiene `Func <>` como parámetro?

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

SearchViewModel con la inyección de constructor:

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 pregunta: ¿Cómo registrarSearchViewModel que tiene Fun<> como parámetro?

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

El código anterior funciona solo sin INewObject.

El objetivo: fábrica se resuelven con InjectionConstructor y resolver INewObject, INewObject2, INewObject3 automáticamente (como sin parámetros: RegisterType<SearchViewModel>()).

¿Es posible? Quizás alternos?

+1

¿Por qué no utilizas la inyección Setter para los parámetros de INewObject? – daryal

+0

¿Por qué hace que SearchViewModel dependa de Func ? ¿No es la abstracción con fugas? Creo que deberías inyectar directamente la interfaz de IDownloader. La implementación concreta de IDownloader puede encapsular el comportamiento de fábrica. Vea el ejemplo del código aquí: http://stackoverflow.com/questions/9757953/can-any-of-existing-ioc-containers-create-the-lazy-proxy-classes-dynamically –

Respuesta

8

que han resuelto el problema:

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

nueva func es una clave, porque antes de que intentara:

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

también la mejor manera de utilizar IDownloaderFactory en lugar de Func<IDownloader> downloaderFactory. IDownloaderFactory puede encapsular el delegado.

También creo que usar un delegado como dependencia dentro de fábrica es una mejor solución que una raíz de composición dañada.

2

El patrón generalmente aceptado para usar aquí es declarar una fábrica abstracta y hacerlo un poco más explícito:

public interface IDownloaderFactory 
{ 
    IDownloader Create(); 
} 

a continuación, crear una clase para representar la fábrica que simplemente utiliza el contenedor de nuevo para resolver casos:

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

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

uso de este enfoque es más explícito y más juega muy bien con los contenedores, también todavía mantiene el recipiente lejos de su aplicación y la lógica de negocio, ahora sólo se necesita un pequeño ajuste a su clase 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()); 
    } 

}

Ahora se puede ver simplemente funciona y crea nuevos casos cada vez.

Configuración del contenedor se vería así:

 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>(); 

en cuenta que es necesario registrar la instancia del contenedor que está trabajando para que la fábrica tiene la misma instancia, ya sea usando este método o una ThreadLocal instancias o algo así.

Nota: también acaba de tener cuidado con el hecho de que el uso del enfoque Func o utilizando el contenedor para resolver el programa de descarga puede provocar efectos no deseados en su cliente. Por ejemplo, si el contenedor está configurado de forma predeterminada para ser transitorio a los objetos de Downloader, se crea una nueva instancia cada vez. Cambiar la duración del contenedor puede hacer que el cliente obtenga la misma instancia cada vez. En tal caso, es mejor construir manualmente el objeto descargador en la fábrica y usar el contenedor solo para los argumentos del descargador.

Cuestiones relacionadas