Pergunta

Então, estou trabalhando no meu contêiner DI/IoC OpenNETCF.IoC e recebi uma solicitação de recurso (razoável) para adicionar alguma forma de gerenciamento do ciclo de vida para itens IDisposable nas coleções de contêineres.

Meu pensamento atual é que, como não posso consultar um objeto para ver se ele foi descartado e não consigo obter um evento para quando ele foi descartado, preciso criar alguma forma de wrapper para objetos que um desenvolvedor deseja a estrutura a ser gerenciada.

No momento, os objetos podem ser adicionados com AddNew (para simplificar, assumiremos que há apenas uma sobrecarga e não há Add):

public TTypeToBuild AddNew<TTypeToBuild>() { ... }

O que estou pensando é adicionar um novo método (bem, agrupe-os, mas você entendeu):

public DisposableWrappedObject<IDisposable> AddNewDisposable<TTypeToBuild>()
    where TTypeToBuild : class, IDisposable
{
    ...
}

Onde o AvailableWrappedObject fica assim:

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

Agora, quando um item é adicionado ao contêiner por meio de AddNewDIsposable, um manipulador de eventos também é adicionado para que, quando for descartado (por meio do wrapper), a estrutura o remova da coleção subjacente.

Na verdade, eu implementei isso e está passando nos testes de unidade, mas estou procurando opiniões sobre onde isso pode estar quebrado ou como pode ser mais "amigável" para o desenvolvedor consumidor.

EDITAR 1

Como houve uma dúvida sobre como o evento Disposing é usado, aqui está um código (reduzido ao que é importante):

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);
}
Foi útil?

Solução

Talvez esteja faltando alguma coisa, mas por que adicionar novos métodos à API?Quando um objeto é adicionado ao contêiner, você pode fazer uma conversão para verificar se é IDisposable e tratá-lo adequadamente se for o caso.

Também estou me perguntando se você precisa do destruidor.Presumindo que o contêiner seja IDisposable (como o do Unity), você poderia simplesmente implementar o Padrão de descarte básico e economize muita sobrecarga de GC.

Algumas perguntas que podem ser aplicáveis:

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top