DI: Обработка жизни идентифицируемых объектов - PullRequest
8 голосов
/ 13 октября 2009

Итак, я работаю над моим 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

Поскольку возник вопрос о том, как используется событие Disposing, вот некоторый код (обрезанный до того, что важно):

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);
}

1 Ответ

3 голосов
/ 13 октября 2009

Может быть, я что-то упускаю, но зачем добавлять новые методы в API? Когда объект добавляется в контейнер, вы можете проверить, является ли он IDisposable и обрабатывать его соответствующим образом, если это так.

Мне также интересно, нужен ли вам деструктор. Предполагая, что контейнер является IDisposable (как и Unity), вы можете просто реализовать Basic Dispose Pattern и сэкономить много накладных расходов GC.

Некоторые вопросы, которые могут быть применимы:

...