在 Autofac 中,如何更改调用 Build 后注册的实例?
Posted
技术标签:
【中文标题】在 Autofac 中,如何更改调用 Build 后注册的实例?【英文标题】:In Autofac how do I change the instance that is registered after Build has been called? 【发布时间】:2011-04-26 18:29:43 【问题描述】:假设我有这个代码
var builder = new ContainerBuilder();
builder.RegisterInstance(new MyType());
var container = builder.Build();
然后一段时间后,我想更改 MyType
的实例,以用于在 container
上调用的所有未来解析。
【问题讨论】:
【参考方案1】:您还可以利用 Autofac Lifetime 事件“OnActivating”,并在内存中拥有自己的控制器对象,以像这样替换已解析的实例
builder.Register<TInterface>(c => c.Resolve<TConcrete>())
.OnActivating(e => e.ReplaceInstance(new TInterfaceSubclass()));
https://autofaccn.readthedocs.io/en/latest/lifetime/events.html#onactivating
【讨论】:
【参考方案2】:另一种方法是注册一个能够更改容器提供的底层实例的委托。考虑以下代码:
var theInstance = new MyType();
var builder = new ContainerBuilder();
builder.Register(context => theInstance);
builder.Register<Action<MyType>>(context => newInstance => theInstance = newInstance);
var container = builder.Build();
您现在可以解析操作以获取可以更改注册的委托:
var updateInstance = c.Resolve<Action<MyType>>();
updateInstance(new MyType());
注意:如果您能详细说明何时以及为什么需要更改实例,或许我们甚至可以找到更好的解决方案。
【讨论】:
当有 500 个单元测试用例要运行时,我认为为每个用例重新构建容器将是低效的。在这种情况下,跨案例覆盖服务是一种重要的解决方法。 @JijieChen 那500个单元测试,他们真的需要一个完整的容器才能运行吗?如果是这样,我会觉得我在这些测试中做的太多了,因此它们更类似于集成测试而不是单元测试。 嗯,我部分同意你的观点,这些案例更像是集成测试。考虑一个类C
有 5 个依赖项,在单元测试场景中,您需要声明这些对象并将它们手动播种到 C
中。在重构期间,您很可能需要更改所有测试用例……这很昂贵。通过重用从 DI 解析的依赖实例和覆盖您想要自定义以满足您的测试用例的依赖实例,这是一种平衡。
@JijieChen 我同意,这可能是维护问题。尽管有人可能会争辩说,过多的依赖项实际上是一种代码味道,并且可能表明您的类做的太多了。但我猜这是对另一个线程的讨论。【参考方案3】:
在要更改注册的时候,新建一个ContainerBuilder
,注册新实例,调用Update
传入容器:
// at some later point...
builder = new ContainerBuilder();
builder.RegisterInstance(myType2);
builder.Update(container);
【讨论】:
更新(容器)已过时。建议重建容器。 当有 500 个单元测试用例要运行时,我认为为每个用例重新构建容器会非常低效。在这种情况下,跨案例覆盖服务是一种重要的解决方法。 仅供参考,请参阅此讨论github.com/autofac/Autofac/issues/811#issuecomment-272428072以上是关于在 Autofac 中,如何更改调用 Build 后注册的实例?的主要内容,如果未能解决你的问题,请参考以下文章
在 if 逻辑中调用同一接口和实现的 Autofac 多个实现