我有一个进行数据处理的应用程序。有
class Pipeline {
IEnumerable<IFilter> Filters {get; set;}
我将过滤器实现注册为
builder.RegisterType<DiversityFilter>().As<IFilter>();
builder.RegisterType<OverflowFilter>().As<IFilter>();
...
到目前为止一切顺利。现在,为了实验和微调,我希望能够使用程序(脚本)覆盖配置文件中的任何过滤器实现,该程序将从stdin读取数据,处理它并将数据发送到stdout。我已经实现了一个带有“fileName”,“args”和“insteadOf”自定义属性的模块,用xml描述模块并调用它。
在模块中我注册了我的“ExecutableFilter”但是如何让它“而不是”所需的服务?如果我尝试这样做:
builder.RegisterType<ExecutableFilter>().As<DiversityFilter>()
然后我得到一个例外“类型'ExecutableFilter'不能分配给服务'DiversityFilter'。”好的,这是合乎逻辑的。但那么我有什么选择呢?
答案 0 :(得分:9)
一旦你用你的线控覆盖IFilter“After”的注册,你将无法从容器中解析它,因为新注册将被激活,因此循环查找。
相反,创建并注册一个挂钩到过滤器创建的模块,并用'wire tapped'替换实例:
class WiretapModule : Module
{
override void AttachToComponentRegistration(
IComponentRegistration registration,
IComponentRegistry registry)
{
if (registration.Services.OfType<KeyedService>().Any(
s => s.ServiceKey == After && s.ServiceType == typeof(IFilter)))
{
registration.Activating += (s, e) => {
e.Instance = new WireTap((IFilter)e.Instance, new ExecuteProvider(fileName, args))
};
}
}
}
(交叉发布到Autofac小组:https://groups.google.com/forum/#!topic/autofac/yLbTeuCObrU)
答案 1 :(得分:2)
您所描述的是部分容器工作,部分业务逻辑。面临的挑战是在这里保持关注点分离。 IMO,容器应该做它应该做的事情,即构建和提供实例或其集合。在这种情况下,它不应该“代替”。我宁愿用足够的信息“丰富”服务,以便管道做出决定。
通过使ExecutableFilter
实现更加独特的界面,可以实现“丰富”。
interface IInsteadOfFilter : IFilter { }
...
builder.RegisterType<ExecutableFilter>().As<IFilter>();
...
class Pipeline
{
IEnumerable<IFilter> Filters {get;set;}
public void DoTheFiltering()
{
var filters = Filters.OfType<IInsteadOfFilter>();
if (!insteadof.Any())
filters = Filters;
foreach(var filter in filters)
{
...
}
}
你也可以使用the metadata infrastructure来解决这个问题,这为我们提供了一种更具表现力的差异化服务方式。