Unity 2.0 e manipulação de tipos de IDisposable (especialmente com PerThreadLifetimeManager)

Sei que perguntas semelhantes foram feitas várias vezes (por exemplo:aqui, aqui,aqui eaqui), mas era para versões anteriores do Unity que a resposta dependia do usoLifetimeManager classe.

A documentação diz:

O Unity usa tipos específicos que herdam da classe base LifetimeManager (coletivamente denominados gerenciadores de duração) para controlar como ele armazena referências a instâncias de objetos e como o contêiner descarta essas instâncias.

Ok, parece bom, então decidi verificar a implementação do build em gerentes vitalícios. Minha conclusão:

TransientLifetimeManager - sem manipulação de descarte. O contêiner resolve apenas a instância e não o rastreia. O código de chamada é responsável por descartar a instância.ContainerControlledLifetimeManager - descarta o momento em que o gerente vitalício é descartado (= quando o recipiente é descartado). Fornece instância singleton compartilhada entre todos os contêineres no hiearchy.HierarchicalLifetimeManager - deriva comportamento deContainerControlledLifetimeManager. Ele fornece instância "singleton" por contêiner no hiearchy (subcontêineres).ExternallyControlledLifetimeManager - sem manipulação de descarte. Corrija o comportamento porque o contêiner não é proprietário da instância.PerResolveLifetimeManager - sem manipulação de descarte. Geralmente é o mesmo queTransientLifetimeManager mas permite reutilizar a instância para injeção de dependência ao resolver todo o gráfico de objetos.PerThreadLifetimeManager - não manuseio do descarte, como também descrito no MSDN.Quem é responsável pelo descarte?

Implementação de build-inPerThreadLifetimeManager é:

public class PerThreadLifetimeManager : LifetimeManager
{
    private readonly Guid key = Guid.NewGuid();
    [ThreadStatic]
    private static Dictionary<Guid, object> values;

    private static void EnsureValues()
    {
        if (values == null)
        {
            values = new Dictionary<Guid, object>();
        }
    }

    public override object GetValue()
    {
        object result;
        EnsureValues();
        values.TryGetValue(this.key, out result);
        return result;
    }

    public override void RemoveValue()
    { }

    public override void SetValue(object newValue)
    {
        EnsureValues();
        values[this.key] = newValue;
    }
}

Portanto, o descarte de contêiner não descarta as instâncias descartáveis criadas com esse gerenciador vitalício. A conclusão do encadeamento também não descartará essas instâncias. Então, quem é responsável por liberar instâncias?

Tentei descartar manualmente a instância resolvida no código e encontrei outro problema. Não posso derrubar o instnace. RemoveValue do gerente da vida útil está vazio - depois que a instância é criada, não é possível removê-lo do dicionário estático do encadeamento (também suspeito queTearDown método não faz nada). Então, se você ligarResolve depois de descartar a instância, você será descartada. Eu acho que isso pode ser um grande problema ao usar esse gerenciador vitalício com threads do pool de threads.

Como usar corretamente esse gerente vitalício?

Além disso, essa implementação é frequentemente reutilizada no ciclo de vida personalizado, e gerentes como PerCallContext, PerHttpRequest, PerAspNetSession, PerWcfCall, etc. Somente o dicionário estático de thread é substituído por alguma outra construção.

Também entendo corretamente que o manuseio de objetos descartáveis depende do gerenciador da vida útil? Portanto, o código do aplicativo depende do gerenciador vitalício usado.

Li que em outros contêineres de IoC que lidam com objetos descartáveis temporários é tratado por subcontêineres, mas não encontrei exemplo para o Unity - ele provavelmente poderia ser tratado com subcontêiner com escopo local eHiearchicalLifetimeManager mas não tenho certeza de como fazê-lo.

questionAnswers(4)

yourAnswerToTheQuestion