Д.И.:Обработка жизни IDisposable объектов
-
21-09-2019 - |
Вопрос
Итак, я работаю над своим контейнером DI/IoC. OpenNETCF.IoC и у меня есть (разумный) запрос на добавление некоторой формы управления жизненным циклом для элементов IDisposable в коллекциях контейнеров.
В настоящее время я думаю, что, поскольку я не могу запросить объект, чтобы узнать, был ли он удален, и я не могу получить событие, когда он был удален, мне нужно создать некоторую форму оболочки для объектов, которые хочет разработчик. рамки для управления.
Сейчас объекты можно добавлять с помощью AddNew (для простоты будем считать, что есть только одна перегрузка и нет Add):
public TTypeToBuild AddNew<TTypeToBuild>() { ... }
Я рассматриваю возможность добавления нового метода (ну, группы из них, но вы поняли):
public DisposableWrappedObject<IDisposable> AddNewDisposable<TTypeToBuild>()
where TTypeToBuild : class, IDisposable
{
...
}
Где DisposableWrappedObject выглядит следующим образом:
public class DisposableWrappedObject<T>
where T : class, IDisposable
{
public bool Disposed { get; private set; }
public T Instance { get; private set; }
internal event EventHandler<GenericEventArgs<IDisposable>> Disposing;
internal DisposableWrappedObject(T disposableObject)
{
if (disposableObject == null) throw new ArgumentNullException();
Instance = disposableObject;
}
~DisposableWrappedObject()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
lock(this)
{
if(Disposed) return;
EventHandler<GenericEventArgs<IDisposable>> handler = Disposing;
if(handler != null)
{
Disposing(this, new GenericEventArgs<IDisposable>(Instance));
}
Instance.Dispose();
Disposed = true;
}
}
}
Теперь, когда элемент добавляется в контейнер через AddNewDIsposable, также добавляется обработчик событий, так что при его удалении (через оболочку) платформа удаляет его из базовой коллекции.
На самом деле у меня это реализовано, и оно проходит модульные тесты, но я ищу мнения о том, где это может быть сломано или как это можно сделать более «дружественным» для разработчика-потребителя.
РЕДАКТИРОВАТЬ 1
Поскольку возник вопрос о том, как используется событие Dispose, вот некоторый код (обрезанный до важного):
private object AddNew(Type typeToBuild, string id, bool wrapDisposables)
{
....
object instance = ObjectFactory.CreateObject(typeToBuild, m_root);
if ((wrapDisposables) && (instance is IDisposable))
{
DisposableWrappedObject<IDisposable> dispInstance = new
DisposableWrappedObject<IDisposable>(instance as IDisposable);
dispInstance.Disposing += new
EventHandler<GenericEventArgs<IDisposable>>(DisposableItemHandler);
Add(dispInstance as TItem, id, expectNullId);
instance = dispInstance;
}
....
return instance;
}
private void DisposableItemHandler(object sender, GenericEventArgs<IDisposable> e)
{
var key = m_items.FirstOrDefault(i => i.Value == sender).Key;
if(key == null) return;
m_items.Remove(key);
}
Решение
Возможно я что-то упускаю, но зачем добавлять в API новые методы?Когда объект добавляется в контейнер, вы можете выполнить приведение as, чтобы проверить, является ли он IDisposable, и обработать его соответствующим образом, если это так.
Мне также интересно, нужен ли вам деструктор.Предполагая, что контейнер является IDisposable (как в Unity), вы можете просто реализовать Базовый шаблон утилизации и сэкономить много накладных расходов на сбор мусора.
Некоторые вопросы, которые могут быть применимы: