Мне все еще было бы интересно узнать, есть ли более элегантное решение для этого с Unity

олезная статья от David Haydn (EDIT: удалена мошенническая ссылка, возможно,эта статья) показывает, как вы можете использоватьInjectionConstructor класс, чтобы помочь вам создать цепочку, используя шаблон декоратора с Unity. Однако, если элементы в вашей цепочке декораторов имеют другие параметры в своем конструкторе,InjectionConstructor должен явно объявить каждый из них (или Unity будет жаловаться, что не может найти правильный конструктор). Это означает, что вы не можете просто добавить новые параметры конструктора к элементам в цепочке декораторов, не обновив при этом код конфигурации Unity.

Вот пример кода, чтобы объяснить, что я имею в виду.ProductRepository класс оборачивается первымCachingProductRepository а затемLoggingProductRepostiory, И CachingProductRepository, и LoggingProductRepository, помимо принятия IProductRepository в своем конструкторе, также нуждаются в других интерфейсах из контейнера.

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

Вот (проходной) модульный тест. Посмотрите комментарии для битов излишней конфигурации, которые я хочу устранить:

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

Ответы на вопрос(6)

Ваш ответ на вопрос