Este útil artículo de David Haydn (EDITAR: se eliminó el enlace fraudulento, pudo haber sido this article) muestra cómo puede usar la clase InjectionConstructor
para ayudarlo configura una cadena usando el patrón de decorador con Unity. Sin embargo, si los elementos en su cadena decoradora tienen otros parámetros en su constructor, el InjectionConstructor
debe declarar explícitamente 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 en la cadena de decoradores sin actualizar también su código de configuración de Unity.Cómo uso el Patrón Decorador con Unity sin especificar explícitamente cada parámetro en InjectionConstructor
Aquí hay un código de ejemplo para explicar a qué me refiero. La clase ProductRepository
está envuelta primero por CachingProductRepository
y luego por LoggingProductRepostiory
. 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 de unidad (pasajera). Véanse los comentarios de los bits de configuración del excedente 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>());
}
así, nunca he usado la unidad antes y tal vez esto está muy lejos, pero no se puede utilizar en lugar de injectionfactory injectionconstructor? – DarkSquirrel42
@ DarkSquirrel42 una sugerencia interesante. La Acción, presumiblemente, tendría que llamar al constructor concreto, lo que significa que el código de configuración de Unity debería llamarse siempre que el construtor cambiara. Sin embargo, al menos generaría un error de compilación, lo que alertaría sobre la necesidad de un cambio. –
@ DarkSquirrel42, pensándolo bien, si solo usa una sola InjectionFactory cuya Func construye toda la cadena, usar el contenedor para cumplir otras dependencias, aunque todavía no esté aislado de los cambios en los parámetros del constructor, es al menos mucho menos confuso que mi original código, y requiere solo un registro en el contenedor también. –