繁体   English   中英

使用Autofac进行嵌套注册

[英]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中使用显式参数FirstLineWorkerSecondLineWorker以编程方式将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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM