这也经常让我感到困惑。尽管对此并不满意,但我始终得出结论,最好不要以瞬时方式返回 IDisposable 对象。
最近,我为自己重新表述了这个问题:这真的是 IoC 问题,还是 .net 框架问题?无论如何,处理都很尴尬。它没有有意义的功能目的,只有技术目的。所以这更多是我们必须处理的框架问题,而不是 IoC 问题。
我喜欢 DI 的地方在于,我可以要求一份合同为我提供功能,而不必担心技术细节。我不是业主。不知道它在哪一层。不知道履行合同需要哪些技术,不担心寿命。我的代码看起来很干净,并且是高度可测试的。我可以在它们所属的层中实现职责。
所以如果这条规则有一个例外需要我组织生命周期,让我们做那个例外。不管我喜不喜欢。如果实现接口的对象需要我处理它,我想知道它,从那时起我被触发使用尽可能短的对象。通过使用稍后处理的子容器来解决它的技巧可能仍然会导致我保持对象的存活时间超过我应该的时间。对象的允许生存期是在注册对象时确定的。不是通过创建子容器并将其保留一段时间的功能。
因此,只要我们开发人员需要担心处置(这会改变吗?),我会尝试注入尽可能少的临时一次性对象。1. 我尝试使对象不是 IDisposable,例如不将一次性对象保持在类级别,而是在较小的范围内。2. 我尝试使对象可重用,以便可以应用不同的生命周期管理器。
如果这不可行,我使用工厂来表明注入合约的用户是所有者,应该对此负责。
有一个警告:将合同实施者从非一次性更改为一次性将是一个重大变化。那时接口将不再注册,而是工厂接口。但我认为这也适用于其他场景。从那一刻起,忘记使用子容器就会产生内存问题。工厂方法将导致 IoC 解析异常。
一些示例代码:
using System;
using Microsoft.Practices.Unity;
namespace Test
{
// Unity configuration
public class ConfigurationExtension : UnityContainerExtension
{
protected override void Initialize()
{
// Container.RegisterType<IDataService, DataService>(); Use factory instead
Container.RegisterType<IInjectionFactory<IDataService>, InjectionFactory<IDataService, DataService>>();
}
}
#region General utility layer
public interface IInjectionFactory<out T>
where T : class
{
T Create();
}
public class InjectionFactory<T2, T1> : IInjectionFactory<T2>
where T1 : T2
where T2 : class
{
private readonly IUnityContainer _iocContainer;
public InjectionFactory(IUnityContainer iocContainer)
{
_iocContainer = iocContainer;
}
public T2 Create()
{
return _iocContainer.Resolve<T1>();
}
}
#endregion
#region data layer
public class DataService : IDataService, IDisposable
{
public object LoadData()
{
return "Test data";
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
/* Dispose stuff */
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
#endregion
#region domain layer
public interface IDataService
{
object LoadData();
}
public class DomainService
{
private readonly IInjectionFactory<IDataService> _dataServiceFactory;
public DomainService(IInjectionFactory<IDataService> dataServiceFactory)
{
_dataServiceFactory = dataServiceFactory;
}
public object GetData()
{
var dataService = _dataServiceFactory.Create();
try
{
return dataService.LoadData();
}
finally
{
var disposableDataService = dataService as IDisposable;
if (disposableDataService != null)
{
disposableDataService.Dispose();
}
}
}
}
#endregion
}