我在Autofac(v4.4.0,.NET 4.6.1)中遇到了一些意外行为,我觉得这可能是一个错误。
默认注册
如果多个组件公开同一服务, Autofac将使用最后注册的组件作为该服务的默认提供商:
e.g。如果我这样做:
builder.RegisterType<FooOne>().As<IFoo>();
// Next line replaces default IFoo implementation
builder.RegisterType<FooTwo>().As<IFoo>();
当我从容器中解析FooTwo
时,我希望(并获得)IFoo
的实例。
但是,如果我已经注册了IFoo
,并且我使用RegisterDecorator<T>
函数注册IFoo
的装饰器,则不会替换默认注册IFoo
。 e.g:
// 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");
将IFoo
解析为 未修饰 FooOne
。这感觉与我不一致;违反了principle of least astonishment。
您可能声称我根本不应该使用第(1)行(并且代码在没有它的情况下正常工作) - 但它是一个公认的习惯用法(例如here)来使用用于替换注册的插件。
在我的情况下,这个bug在一个相当大的代码库中得到满足,其中包装类型已经由一个约定注册,现在需要进行修饰,需要重新考虑如何完成注册。
适用于LINQPad的Gist证明问题是here。
我缺少观察到的行为的设计理由吗?有没有办法让装饰器注册替换默认值?
答案 0 :(得分:4)
您可以查看有关您的问题here的未解决问题。在讨论中你可以找到这种行为背后的推理。正如我所理解的那样,他们正试图解决这个问题,但事实证明,由于autofac的内部运作,这并不是一件容易的事。
同时作为一种解决方法,您可以像这样注册您的装饰者:
builder.Register((cnt, parameters) => new DecoratorFoo(cnt.ResolveNamed<IFoo>("foo", parameters))).As<IFoo>();
这也将修复另一个问题\ bug(在此stackoverflow question中提到),您可能会遇到(或不会)以后,与事实相关的装饰器不会将参数传播到装饰对象。