使用Autofac进行嵌套注册

时间:2017-01-05 07:26:18

标签: c# .net dependency-injection autofac

我试图将一个类注册为一个特定的接口,并使用显式类作为其构造函数的参数。问题是它们都实现了相同的接口,当前的注册结束时,Autofac"循环组件依赖检测到#34;。

这是我得到的:

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中以编程方式将 SequentialWorker 注册为 IWorker ,并使用显式参数 FirstLineWorker SecondLineWorker

最初进行循环重新编译的第一次尝试是:

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();

有什么想法吗?

2 个答案:

答案 0 :(得分:1)

至少有两种方法可供您使用。首先,创建一个新的空接口,派生自IWorker,如

public interface IWorkExecutor : IWorker { }

然后,注册&#34;正常&#34;工人为IWorker,&#34;执行人员&#34;作为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)) }));

您必须在params IWorker[] workers中传递SequentialWorker的单个数组参数。

实际上并不需要BTW InstancePerDependency(),因为这是注册类型时的默认生命周期范围。

答案 1 :(得分:1)

部分由this关于复合模式的问题(这是你在这里实现的)回答。

解决方案是使用通用名称注册所有服务,并在复合注册中解析命名集合:

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,因为它无需在解析ToArray()时执行"worker"

public SequentialWorker(IEnumerable<IWorker> workers)
{
    _workers = workers;
}
相关问题