在 Autofac 中,如何用装饰器替换默认注册?

Jam*_*rld 5 c# autofac

我在 Autofac(v4.4.0,.NET 4.6.1)中遇到了一些意想不到的行为,我觉得这可能是一个错误。

文档

默认注册

如果多个组件公开相同的服务,Autofac 将使用最后注册的组件作为该服务的默认提供者

例如,如果我这样做:

    builder.RegisterType<FooOne>().As<IFoo>();
    // Next line replaces default IFoo implementation
    builder.RegisterType<FooTwo>().As<IFoo>();
Run Code Online (Sandbox Code Playgroud)

我期望(并获得)FooTwoIFoo从容器解析的实例。

但是,如果我已经注册了IFoo,并且我使用该RegisterDecorator<T>函数注册了 的装饰器IFoo,则它不会替换 的默认注册IFoo。例如:

    // Register FooOne directly
    builder.RegisterType<FooOne>().As<IFoo>(); // (1)
    // Now set up a decorator
    builder.RegisterType<FooOne>().Named<IFoo>("foo");
    builder.RegisterDecorator<IFoo>((c, inner) =>
      new DecoratorFoo(inner), fromKey: "foo");
Run Code Online (Sandbox Code Playgroud)

将解析IFoo未修饰的 FooOne. 这让我感觉不一致;违反了最小惊讶原则

您可能会声称我根本不应该使用第 (1) 行(如果没有它,代码也能正常工作)——但使用插件来替换注册是一种公认​​的习惯用法(例如此处)。

在我的例子中,这个错误在一个相当大的代码库中表现出来,其中包装类型已经通过约定注册,现在需要进行装饰,需要重新考虑如何完成注册。

适合LINQPad演示该问题,要旨是在这里

我缺少的观察到的行为是否有任何设计原因?有没有办法让装饰器注册替换默认值?

Evk*_*Evk 5

您可以在此处查看有关您的问题的未解决问题。在讨论中,您可以找到这种行为背后的原因。据我所知,他们正试图解决这个问题,但事实证明,由于 autofac 的内部工作原理,这并不是一件小事。

同时,作为一种解决方法,您可以像这样注册装饰器:

builder.Register((cnt, parameters) => new DecoratorFoo(cnt.ResolveNamed<IFoo>("foo", parameters))).As<IFoo>();
Run Code Online (Sandbox Code Playgroud)

这也将修复另一个问题\错误(在这个stackoverflow question 中提到),您稍后可能会遇到(或不会),与事实相关的装饰器不会将参数向前传播到装饰对象。