我有一个问题,我将标记这个主观,因为这是我认为它演变成更多的讨论.我希望有一些好主意或一些思想家.我为这个冗长的问题道歉,但你需要了解背景.
问题基本上是:
您如何处理与IoC容器相关的具体类型?具体而言,谁负责处理它们,如果它们需要处置,以及这些知识如何传播到调用代码?
你要求它们是IDisposable吗?如果没有,该代码是否面向未来,或者是您不能使用一次性对象的规则?如果您对接口和具体类型强制执行IDisposable-requirements以便面向未来,那么它的责任是作为构造函数调用的一部分注入的对象?
编辑:我接受了@Chris Ballard的回答,因为它是我们最终接近的方法.
基本上,我们总是返回一个如下所示的类型:
public interface IService: IDisposable where T: class { T Instance { get; } Boolean Success { get; } String FailureMessage { get; } // in case Success=false }
然后我们从.Resolve和.TryResolve返回一个实现此接口的对象,这样我们在调用代码中得到的内容总是相同的类型.
现在,实现此接口的对象IService
是IDisposable,应始终处理掉.程序员无法解析服务以决定是否IService
应该处置对象.
然而,这是至关重要的部分,无论服务实例是否应该被处置,知识被烘焙到实现的对象中IService
,因此如果它是工厂范围的服务(即,每次调用Resolve都会以新的服务实例结束) ),然后在处理IService
对象时处理服务实例.
这也使得支持其他特殊范围成为可能,例如汇集.我们现在可以说我们需要最少2个服务实例,最多15个,通常为5个,这意味着每次调用.Resolve都将从可用对象池中检索服务实例,或者构造一个新实例.然后,当处理IService
保存池化服务的对象时,服务实例将被释放回其池中.
当然,这使得所有代码看起来像这样:
using (var service = ServiceContainer.Global.Resolve()) { service.Instance.DoSomething(); }
但它是一种干净的方法,无论使用何种服务或具体对象,它都具有相同的语法,因此我们选择它作为可接受的解决方案.
对于子孙后代,原始问题如下
冗长的问题来到这里:
我们有一个IoC容器,最近我们发现了一个问题.
在非IoC代码中,当我们想要使用一个文件时,我们使用了这样的类:
using (Stream stream = new FileStream(...)) { ... }
毫无疑问,这个类是否是一个资源有限的东西,因为我们知道必须关闭文件,并且类本身实现了IDisposable.规则很简单,我们构造实现IDisposable的对象的每个类都必须被处理掉.无话可问.这个类的用户不能决定调用Dispose是否是可选的.
好的,那么迈向IoC容器的第一步.让我们假设我们不希望代码直接与文件对话,而是通过一层间接.对于这个例子,我们将这个类称为BinaryDataProvider.在内部,类正在使用流,它仍然是一次性对象,因此上面的代码将更改为:
using (BinaryDataProvider provider = new BinaryDataProvider(...)) { ... }
这没有太大变化.该类实现IDisposable的知识仍在这里,没有问题,我们需要调用Dispose.
但是,我们假设我们有提供数据的类,现在不使用任何这样有限的资源.
上面的代码可以写成:
BinaryDataProvider provider = new BinaryDataProvider(); ...
好的,到目前为止一切顺利,但问题的关键在于此.假设我们想要使用IoC容器来注入此提供程序,而不是依赖于特定的具体类型.
代码将是:
IBinaryDataProvider provider = ServiceContainer.Global.Resolve(); ...
请注意,我假设有一个可用的独立接口,我们可以通过它访问该对象.
通过上述更改,如果我们以后想要使用真正应该处理的对象怎么办?没有解析该接口的现有代码被写入处理对象,那么现在呢?
我们看待它的方式,我们必须选择一个解决方案:
实现运行时检查,检查正在注册的具体类型是否实现IDisposable,要求它通过它公开的接口也实现IDisposable.这不是一个好的解决方案
在对所使用的接口进行约束之前,它们必须始终从IDisposable继承,以便面向未来
强制运行时没有具体类型可以是IDisposable,因为使用IoC容器的代码没有特别处理
只需将其留给程序员来检查对象是否实现了IDisposable并"做正确的事"?
还有其他人吗?
那么,在构造函数中注入对象呢?我们的容器以及我们研究过的其他一些容器能够将新对象注入到具体类型的构造函数的参数中.例如,如果我们BinaryDataProvider
需要一个实现ILogging
接口的对象,如果我们对这些对象强制执行IDispose-"ability",那么它的职责是处理日志记录对象?
你怎么看?我想要意见,无论好坏.