因此,我正在尝试实现拦截的概念,同时使用autofac。我没有做任何花哨的事情,比如实现动态拦截,我的每个类都有具体的代码。
我的代码(不是我真正的代码,这是我在网上找到的,但它说明了我的问题
public class DefaultProductService : IProductService
{
public Product GetProduct(int productId)
{
return new Product();
}
}
public class CachedProductService : IProductService
{
private readonly IProductService _innerProductService;
private readonly ICacheStorage _cacheStorage;
public CachedProductService(IProductService innerProductService, ICacheStorage cacheStorage)
{
if (innerProductService == null) throw new ArgumentNullException("ProductService");
if (cacheStorage == null) throw new ArgumentNullException("CacheStorage");
_cacheStorage = cacheStorage;
_innerProductService = innerProductService;
}
public Product GetProduct(int productId)
{
string key = "Product|" + productId;
Product p = _cacheStorage.Retrieve<Product>(key);
if (p == null)
{
p = _innerProductService.GetProduct(productId);
_cacheStorage.Store(key, p);
}
return p;
}
}
public class ProductManager : IProductManager
{
private readonly IProductService _productService;
public ProductManager(IProductService productService)
{
_productService = productService;
}
}我的问题是,我希望我的ProductManager接收IProductService的" CachedProductService“,我希望我的CachedProductService接收IProductService的"DefaultProductService”。
我知道一些解决方案,但似乎没有一个是完全正确的。这样做的正确方法是什么?
谢谢!迈克尔
发布于 2016-06-23 02:01:40
您可以使用named dependencies来完成此操作。
不是说IProductService的实现是DefaultProductService,您将有两个通过它们的名称来区分的实现,如下所示:
builder.Register<DefaultProductService>().Named<IProductService>("DefaultProductService");
builder.Register<CachedProductService>().Named<IProductService>("CachedProductService");文档中描述了几种不同的方法来指示您想要将哪个实现注入到给定的类中。这看起来像是最简单和最明确的:
public class ProductManager : IProductManager
{
private readonly IProductService _productService;
public ProductManager([WithKey("CachedProductService")]IProductService productService)
{
_productService = productService;
}
}老实说,我不喜欢它,因为它会导致类依赖于容器。它不允许您将其与类本身完全分开进行配置。使用Windsor,您可以在向容器注册依赖项时执行此操作,告诉容器使用哪个命名依赖项。
但这应该是可行的。
发布于 2016-06-23 15:12:04
您尝试做的似乎不是一个拦截概念,而是一个装饰器概念。
在面向对象的编程中,装饰器模式是一种设计模式,它允许静态或动态地将行为添加到单个对象,而不会影响同一类中其他对象的行为。来自

Autofac内置了对使用命名注册的装饰器的支持。
首先,您必须将基本组件和装饰器声明为命名注册:
builder.RegisterType<DefaultProductService>().Named<IProductService>("base");
builder.RegisterType<CacheProductServiceAdapter>().Named<IProductService>("cache"); 然后你就可以注册你的装饰器了
builder.RegisterDecorator((c, inner) => c.ResolveNamed<IProductService>("cache", TypedParameter.From(inner)), fromKey : "base")
.As<IProductService>(); 您还可以有多个适配器:
builder.RegisterType<DefaultProductService>().Named<IProductService>("base");
builder.RegisterType<CacheProductServiceAdapter>().Named<IProductService>("cache");
builder.RegisterType<LoggingProductServiceAdapter>().Named<IProductService>("logging");
builder.RegisterDecorator((c, inner) => c.ResolveNamed<IProductService>("cache", TypedParameter.From(inner)), fromKey : "base", toKey:"cached");
builder.RegisterDecorator((c, inner) => c.ResolveNamed<IProductService>("logging", TypedParameter.From(inner)), fromKey : "cached")
.As<IProductService>(); 有关详细信息,请参阅adapters and decorators from Autofac documentation。
发布于 2016-06-23 02:41:04
基于Scott的建议,我想我找到了一种方法,而不必在我的ProductManager类中引入对容器的依赖(我真的很讨厌这样做!)。我可以简单地实例化CachedProductService并告诉它使用哪个ProductService
builder.RegisterType(typeof(ProductService)).Named<IProductService>("DefaultProductService");
builder.Register(c => new CachedProductService(c.ResolveKeyed<IProductService>("DefaultProductService"))).As<IProductService>();https://stackoverflow.com/questions/37974821
复制相似问题