¿Cómo uso el patrón de decorador con Unity sin especificar explícitamente cada parámetro en InjectionConstructor

Este útil artículo de David Haydn (EDITAR: enlace de estafa eliminado, podría haber sidoEste artícul) muestra cómo puedes usar laInjectionConstructor class para ayudarlo a configurar una cadena usando el patrón decorador con Unity. Sin embargo, si los elementos en su cadena de decorador tienen otros parámetros en su constructor, laInjectionConstructor debe declarar explícitamente a cada uno de ellos (o Unity se quejará de que no puede encontrar el constructor correcto). Esto significa que no puede simplemente agregar nuevos parámetros de constructor a los elementos de la cadena decoradora sin actualizar también el código de configuración de Unity.

Aquí hay un código de ejemplo para explicar lo que quiero decir. LosProductRepository clase es envuelta primero porCachingProductRepository y luego porLoggingProductRepostiory. Tanto CachingProductRepository como LoggingProductRepository, además de tomar un IProductRepository en su constructor, también necesitan otras interfaces desde el contenedor.

    public class Product 
    {
        public int Id;
        public string Name;
    }

    public interface IDatabaseConnection { }

    public interface ICacheProvider 
    { 
        object GetFromCache(string key);
        void AddToCache(string key, object value);
    }

    public interface ILogger
    {
        void Log(string message, params object[] args);
    }


    public interface IProductRepository
    {
        Product GetById(int id);    
    }

    class ProductRepository : IProductRepository
    {
        public ProductRepository(IDatabaseConnection db)
        {
        }

        public Product GetById(int id)
        {
            return new Product() { Id = id, Name = "Foo " + id.ToString() };
        }
    }

    class CachingProductRepository : IProductRepository
    {
        IProductRepository repository;
        ICacheProvider cacheProvider;
        public CachingProductRepository(IProductRepository repository, ICacheProvider cp)
        {
            this.repository = repository;
            this.cacheProvider = cp;
        }

        public Product GetById(int id)
        {       
            string key = "Product " + id.ToString();
            Product p = (Product)cacheProvider.GetFromCache(key);
            if (p == null)
            {
                p = repository.GetById(id);
                cacheProvider.AddToCache(key, p);
            }
            return p;
        }
    }

    class LoggingProductRepository : IProductRepository
    {
        private IProductRepository repository;
        private ILogger logger;

        public LoggingProductRepository(IProductRepository repository, ILogger logger)
        {
            this.repository = repository;
            this.logger = logger;
        }

        public Product GetById(int id)
        {
            logger.Log("Requesting product {0}", id);
            return repository.GetById(id);
        }
    }

Aquí hay una prueba unitaria (aprobada). Vea los comentarios para los bits de configuración excedente que quiero eliminar la necesidad de:

    [Test]
    public void ResolveWithDecorators()
    {
        UnityContainer c = new UnityContainer();            
        c.RegisterInstance<IDatabaseConnection>(new Mock<IDatabaseConnection>().Object);
        c.RegisterInstance<ILogger>(new Mock<ILogger>().Object);
        c.RegisterInstance<ICacheProvider>(new Mock<ICacheProvider>().Object);

        c.RegisterType<IProductRepository, ProductRepository>("ProductRepository");

        // don't want to have to update this line every time the CachingProductRepository constructor gets another parameter
        var dependOnProductRepository = new InjectionConstructor(new ResolvedParameter<IProductRepository>("ProductRepository"), new ResolvedParameter<ICacheProvider>());
        c.RegisterType<IProductRepository, CachingProductRepository>("CachingProductRepository", dependOnProductRepository);

        // don't want to have to update this line every time the LoggingProductRepository constructor changes
        var dependOnCachingProductRepository = new InjectionConstructor(new ResolvedParameter<IProductRepository>("CachingProductRepository"), new ResolvedParameter<ILogger>());
        c.RegisterType<IProductRepository, LoggingProductRepository>(dependOnCachingProductRepository);
        Assert.IsInstanceOf<LoggingProductRepository>(c.Resolve<IProductRepository>());
    }

Respuestas a la pregunta(6)

Su respuesta a la pregunta