温莎集装箱:如何强制处置物体?
我有一个实现IDisposable的对象,该对象已在Windsor容器中注册,我想对其进行处理,因此将调用Dispose方法,并在下次调用Resolve时获取一个新实例。
做
container.Release(obj);
立即自动调用Dispose()吗?还是我需要做
obj.Dispose(); container.Release(obj);
在文档中找不到有关Release确切功能的任何信息
编辑:
有关我运行的测试结果,请参见下面的答案。现在的问题是,如何强制容器释放具有单例生命周期的组件实例?这只需要在一个地方完成,编写自定义生命周期似乎太繁重了,难道没有内置的方法吗?
解决方案
回答
这取决于我们将其添加到容器中时指定的组件的寿命。
如果生活方式是集中的,则可以使用Release()。这会将组件放回池中,以进行下一次检索(对象不会被销毁,因此处理会很糟糕)
如果生活方式是短暂的,则在获取组件时会创建一个新对象。在这种情况下,处置由我们决定,我们无需致电Release
如果生活方式是Thread,则每个线程都使用相同的组件,而不销毁。
如果生活方式是Singleton,则只会创建一个组件,并且不会破坏它。
我们最有可能正在使用瞬态组件? (如果我们担心及时处理它们)
在这种情况下,只需将其包装成一个using即可,然后我们就可以进行设置(或者将处处处置称为自己)
using(ISomeService service = container.Resolve<ISomeService>()) { // Do stuff here // service.Dispose is automatically called }
编辑是,为了"刷新"或者处置并重新创建单例,我们需要销毁容器或者编写自定义生命周期。进行自定义生命周期实际上并不那么困难,并且将这样做的逻辑保持在一个地方。
回答
好吧,所以我一直在运行测试,似乎Container.Release()
将隐式地导致IDisposable的Dispose()
方法仅在生活方式为瞬态时执行(这可能不完全正确,但重点是如果生活方式是单身,就不会做任何令人毛骨悚然的事情。
现在,如果调用Container.Dispose()
,它将也调用一次性方法,尽管不幸的是,它将丢弃整个内核,并且我们必须将所有组件重新添加回:
var container = new WindsorContainer(); container.AddComponentWithLifestyle<MyDisposable>(Castle.Core.LifestyleType.Singleton); var obj = container.Resolve<MyDisposable>(); // Create a new instance of MyDisposable obj.DoSomething(); var obj2 = container.Resolve<MyDisposable>(); // Returns the same instance as obj obj2.DoSomething(); container.Dispose(); // Will call the Disposable method of obj // Now the components need to be added back in container.AddComponentWithLifestyle<MyDisposable>(Castle.Core.LifestyleType.Singleton); var obj3 = container.Resolve<MyDisposable>(); // Create a new instance of MyDisposable
幸运的是,我有能力删除所有组件,并且可以相当轻松地还原它们。但是,这不是最佳的。
回答
我认为这是人们在使用Windsor容器时并没有真正意识到的事情,尤其是通常令人惊讶的行为,即在内核被使用之前,容器将一次性瞬态组件保留在容器中,直到被处置,除非我们自己释放它们记录在这里,但快速引用:
the MicroKernel has a pluggable release policy that can hook up and implement some routing to dispose the components. The MicroKernel comes with three IReleasePolicy implementations: AllComponentsReleasePolicy: track all components to enforce correct disposal upon the MicroKernel instance disposal LifecycledComponentsReleasePolicy: only track components that have a decommission lifecycle associated NoTrackingReleasePolicy: does not perform any tracking You can also implement your own release policy by using the interface IReleasePolicy.
我们可能会发现更容易的是将策略更改为NoTrackingReleasePolicy,然后自行处理,这也有潜在的风险,但是,如果生活方式是暂时的(或者如果处置容器后应用程序将要关闭,则是这样)可能没什么大不了的。但是请记住,任何已经注入了单例的组件都将保留一个引用,因此我们可能最终会尝试"刷新"单例时出现问题,这似乎是一种不好的做法,我想知道是否可以避免这样做首先,通过改善应用程序的组合方式。
其他方法是使用其自己的停用实现来构建自定义生命周期(因此释放单例实际上将处置组件,就像瞬态生命周期一样)。
另一种方法是在容器中注册具有单一生活方式的装饰器,但在容器中注册的实际基础服务具有短暂的生活方式,那么当我们需要刷新组件时,只需处置由容器持有的临时基础组件即可装饰器并将其替换为新解析的实例(使用components键而不是服务来解析它,以避免获取装饰器),这避免了其他单例服务(不会被"刷新")的问题保持陈旧已经废弃的服务使它们无法使用,但是需要一些转换等才能使其正常工作。