Autofac过滤器解决了IEnumerable实现

时间:2018-05-09 08:48:45

标签: c# .net dependency-injection autofac

在autofac中解析IEnumerable时是否可以过滤依赖关系?

我有一个接口的多个实现(在下面的例子中为IHandler),它们被定义为&在隔离项目中使用Autofac模块注册。我希望能够在解析父类型(下面的示例中为Processor)时过滤实现。

IHandler实现可以注入Processor并在ctor中过滤,但这需要解决所有实现,无论是否需要它们都是浪费。

public interface IHandler { }
public class Handler1 : IHandler { }
public class Handler2 : IHandler { }
public class Handler3 : IHandler { }

public class Processor {
    public IEnumerable<IHandler> Handlers;

    public Processor(IEnumerable<IHandler> handlers) {
        Handlers = handlers;
    }
}

static void Main(string[] args)
{
    var builder = new ContainerBuilder();

    builder.RegisterType<Handler1>().As<IHandler>();
    builder.RegisterType<Handler2>().As<IHandler>();
    builder.RegisterType<Handler3>().As<IHandler>();

    builder.RegisterType<Processor>().AsSelf();

    var container = builder.Build();

    var processor = container.Resolve<Processor>();
}

由于一次只能解决1个密钥,因此使用密钥的尝试无效:

[Flags]
public enum HandlerType
{
    One = 1,
    Two = 2,
    Three = 4
}

builder.RegisterType<Handler1>().Keyed<IHandler>(HandlerType.One);
builder.RegisterType<Handler2>().Keyed<IHandler>(HandlerType.Two);
builder.RegisterType<Handler3>().Keyed<IHandler>(HandlerType.Three);

var enabledHandlers = HandlerType.One | HandlerType.Three;
builder.RegisterType<Processor>().AsSelf()
    .WithParameter(ResolvedParameter.ForKeyed<IEnumerable<IHandler>>(enabledHandlers));

2 个答案:

答案 0 :(得分:1)

如果您可以在容器设置阶段提供适当的过滤器(就像在示例代码中那样),您可以将Processor类型注册更改为以下内容:

builder.RegisterType<Processor>().AsSelf()
    .WithParameter((p, c) => p.Name == "handlers",
        (p, c) => new[] 
            {
                c.ResolveKeyed<IHandler>(HandlerType.One),
                c.ResolveKeyed<IHandler>(HandlerType.Three)
            });

您需要使用的值可以从配置文件中随处获取。

答案 1 :(得分:0)

由于注册的处理程序基于配置开关,这意味着所选的处理程序不会在运行时更改。这与基于某些运行时条件选择处理程序非常不同。因此,我提出类似的建议:

var handlerIds = ConfigurationManager.AppSettings["Handlers"].Split(',');

if (handlerIds.Contains("1")) builder.RegisterType<Handler1>().As<IHandler>();
if (handlerIds.Contains("2")) builder.RegisterType<Handler2>().As<IHandler>();
if (handlerIds.Contains("3")) builder.RegisterType<Handler3>().As<IHandler>();
if (handlerIds.Contains("4")) builder.RegisterType<Handler4>().As<IHandler>();
// etc

builder.RegisterType<Processor>().AsSelf();