[英]Nested registration with Autofac
我试图将一个类注册为特定接口,并使用显式类作为其构造函数的参数。 问题在于它们都实现了相同的接口,在我当前的注册中,该接口最终出现在Autofac“检测到圆形组件依赖项”中。
这是我得到的:
public interface IWorker
{
void DoWork();
}
public class FirstLineWorker : IWorker
{
public void DoWork()
{
//Do some work
}
}
public class SecondLineWorker : IWorker
{
public void DoWork()
{
//Do some morework
}
}
public class SequentialWorker : IWorker
{
private readonly IList<IWorker> _workers;
public SequentialWorker(params IWorker[] workers)
{
_workers = workers;
}
public void DoWork()
{
foreach (var worker in _workers)
{
worker.DoWork();
}
}
}
如何在Autofac中使用显式参数FirstLineWorker和SecondLineWorker以编程方式将SequentialWorker注册为IWorker ?
首次以圆形注册告终的尝试是:
var builder = new ContainerBuilder();
builder
.RegisterType<FirstLineWorker>()
.Named<IWorker>(typeof(FirstLineWorker).Name)
.InstancePerDependency();
builder
.RegisterType<SecondLineWorker>()
.Named<IWorker>(typeof(SecondLineWorker).Name)
.InstancePerDependency();
builder.RegisterType<SequentialWorker>()
.As<IWorker>()
.WithParameter(ResolvedParameter.ForNamed<IWorker>(typeof(FirstLineWorker).Name))
.WithParameter(ResolvedParameter.ForNamed<IWorker>(typeof(SecondLineWorker).Name))
.InstancePerDependency();
有任何想法吗?
至少有两种方法可供您选择。 首先,创建一个继承自IWorker
的新的空接口,例如
public interface IWorkExecutor : IWorker { }
然后,将“普通”工作者注册为IWorker
,将“执行者”注册为IWorkExecutor
builder.RegisterType<Worker1>().As<IWorker>();
builder.RegisterType<Worker2>().As<IWorker>();
builder.RegisterType<SequentialWorker>().As<IWorkExecutor>();
第二种方法与您已有的代码非常相似:
containerBuilder.RegisterType<Worker1>().Named<IWorker>(nameof(Worker1));
containerBuilder.RegisterType<Worker2>().Named<IWorker>(nameof(Worker2));
containerBuilder.RegisterType<SequentialWorker>().As<IWorker>()
.WithParameter(new ResolvedParameter(
(pi, cc) => pi.Name == "workers",
(pi, cc) => new [] { cc.ResolveNamed<IWorker>(nameof(Worker1)), cc.ResolveNamed<IWorker>(nameof(Worker2)) }));
您必须为SequentialWorker
params IWorker[] workers
传递单个数组参数。
实际不需要BTW InstancePerDependency()
,因为这是注册类型时的默认生存期范围。
关于复合模式的问题(在此实现的部分问题)部分回答了这一问题。
解决方案是使用通用名称注册所有服务,并在组合的注册中解析命名集合:
builder
.RegisterType<FirstLineWorker>()
.Named<IWorker>("worker")
.InstancePerDependency();
builder
.RegisterType<SecondLineWorker>()
.Named<IWorker>("worker")
.InstancePerDependency();
还有
builder
.Register<IWorker>(c => new SequentialWorker(
c.ResolveNamed<IEnumerable<IWorker>>("worker").ToArray()))
.As<IWorker>()
.InstancePerDependency();
要么
builder.RegisterType<SequentialWorker>()
.As<IWorker>()
.WithParameter(new ResolvedParameter(
(pi, cc) => pi.Name == "workers",
(pi, cc) => cc.ResolveNamed<IEnumerable<IWorker>>("worker").ToArray()));
还值得一提的是, params
并不是真正必需的,您可以使用IEnumerable
因为它避免了在解决"worker"
时执行ToArray()
的需要。
public SequentialWorker(IEnumerable<IWorker> workers)
{
_workers = workers;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.