Меня это тоже часто озадачивало. Хотя я не был доволен этим, я всегда приходил к выводу, что лучше никогда не возвращать IDisposable объект временным способом.
Недавно я перефразировал вопрос для себя: действительно ли это проблема IoC или проблема .NET Framework? Утилизация в любом случае неудобна. У него нет значимого функционального назначения, только техническое. Так что это скорее проблема структуры, с которой мы должны иметь дело, чем проблема 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
}