这篇来自 David Haydn 的有用文章(编辑:诈骗链接已删除,可能是 this article )展示了如何使用 InjectionConstructor
类来帮助您使用装饰器模式设置链与团结。但是,如果装饰器链中的项在其构造函数中有其他参数,则 InjectionConstructor
必须显式声明它们中的每一个(否则 Unity 会提示找不到正确的构造函数)。这意味着您不能在不更新 Unity 配置代码的情况下简单地向装饰器链中的项目添加新的构造函数参数。
这里有一些示例代码来解释我的意思。 ProductRepository
类首先由 CachingProductRepository
包装,然后由 LoggingProductRepostiory
包装。 CachingProductRepository 和 LoggingProductRepository 除了在其构造函数中采用 IProductRepository 之外,还需要来自容器的其他接口(interface)。
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>());
}
最佳答案
感谢@DarkSquirrel42 的建议,另一种方法是使用 InjectionFactory
。缺点是每次将新的构造函数参数添加到链中的某些内容时,代码仍然需要更新。优点是代码更容易理解,并且只需一次注册到容器中。
Func<IUnityContainer,object> createChain = container =>
new LoggingProductRepository(
new CachingProductRepository(
container.Resolve<ProductRepository>(),
container.Resolve<ICacheProvider>()),
container.Resolve<ILogger>());
c.RegisterType<IProductRepository>(new InjectionFactory(createChain));
Assert.IsInstanceOf<LoggingProductRepository>(c.Resolve<IProductRepository>());
关于c# - 如何在不显式指定 InjectionConstructor 中的每个参数的情况下将 Decorator Pattern 与 Unity 一起使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6109646/