C# - Usando referências fracas - classe WeakRefence


 Neste artigo vou apresentar o conceito de referências fracas e a classe WeakReference e como usá-lo na linguagem C#.

Às vezes, você tem um objeto muito grande e precisa acessá-lo várias vezes, mas não constantemente, ao longo de sua aplicação.

Por exemplo, uma enorme tabela de pesquisa, ou o conteúdo de um arquivo grande que você precisa ler na memória para usar em alguma operação ou algoritmo.

Para trabalhar com este objeto, você tradicionalmente tem duas opções:

1 - Tratar o objeto como uma variável local dentro do método que precisa usar o objeto
2 - Tratar o objeto como um campo em uma classe que vive durante todo o tempo que o objeto é necessário


As duas soluções não são as mais indicadas para objetos muitos grandes. Vejamos porque...

A primeira opção vai diminuir o desempenho da sua aplicação uma vez que o objeto não só precisa ser criado novamente sempre que necessário mas também tem que ser excluido cada vez que ele sai do escopo, gerando um trabalho para o coletor de lixo.

Na segunda solução o objeto é mantido na memória durante todo o tempo, o que pode causar um grande consumo de memória pela sua aplicação.

Se a criação do objeto for muito dispendiosa e você quer evitar fazer isso várias vezes, a primeira solução seria a melhor opção.

Ocorre que a partir da versão 4.0 do Net Framework temos uma opção intermediária onde podemos usar, nestes casos, o recurso da referência fraca disponibilizada pela classe WeakReference.

E como funciona essa tal de referência fraca ?

Geralmente, quando um objeto sai do escopo, ou é definido como nulo, ele não é mais acessível, mesmo que o coletor de lixo apenas elimine o objeto muito mais tarde.

Um objeto de referência fraca manterá uma referência a um objeto que saiu do escopo ou foi definido como nulo, até que ele seja excluído pelo coletor de lixo. Mas até que isso aconteça, podemos recuperar o objeto e usá-lo.

Portanto, nossa nova opção para trabalhar com um objeto grande é usar uma referência fraca.

A referência fraca em si deve se tornar um membro da classe, e no método que precisa do nosso enorme objeto, verificamos se a referência fraca contém um objeto, e se ela contiver vamos usá-la, se não contiver então criamos uma nova instância.

Desta forma, quando executamos o nosso método, uma nova instância do enorme objeto é criada. Mas quando ele for executado novamente, e o coletor de lixo não eliminou o objeto, podemos reutilizar a instância já criada e não precisamos criar uma nova instância.

As referências fracas são úteis para objetos que usam muita memória, mas podem ser recriados facilmente se forem recuperados pela coleta de lixo.

Entendeu ???

Para usar o recurso da referência fraca usamos a classe WeakReference, do namespace System, e fazemos uma chamada de construtor onde você deve passar a referência do objeto para o qual deseja usar.

Ex :   WeakReference wkrf = new WeakReference(SeuObjetoGrande);

Para obter o objeto subjacente de uma referência fraca, usamos sua propriedade .Target que obtém ou define o objeto (o destino) referenciado pelo objeto WeakReference atual.

Ex :    SeuObjetoGrande= wkrf.Target as SuaClasse;

Para saber o objeto atual referenciado já passou pela coleta de lixo usamos a propriedade IsAlive.

Ex:    if (wkrf.IsAlive)..

Recursos Usados neste artigo :

Criando o projeto Console

Abra o VS 2017 Community e crie um projeto do tipo Console App(.NET Framework) chamado CShp_ReferenciaFraca

Abra o arquivo Program.cs e no método Main() defina o código abaixo:

using System;
using System.Text;
using static System.Console;
namespace CShp_ReferenciaFraca
{
    class Program
    {
        /// <summary>
        /// Aponta para dados que podem ser coletados em qualquer momento
        /// </summary>
        static WeakReference _referenciaFraca;
        static void Main(string[] args)
        {
            // atribuir a WeakReference.
            _referenciaFraca = new WeakReference(new StringBuilder("macoratti.net"));
            // verifica se a referência fraca esta 'viva'
            if (_referenciaFraca.IsAlive)
            {
                WriteLine((_referenciaFraca.Target as StringBuilder).ToString());
            }
            // Invoca o coletor de lixo: GC.Collect.
            // ... Se você comentar esta linha de código
            // ....a próxima condição será avaliada como true(dependendo do GC)
            GC.Collect();
            // Verifica se a referência esta ativa(viva)
            if (_referenciaFraca.IsAlive)
            {
                WriteLine("IsAlive");
            }
            // Encerra.
            WriteLine("[Concluído]");
            Read();
        }
    }
}

A propriedade IsAlive é uma propriedade booleana que indica se o objeto apontado pela WeakReference foi coletado ou não.

A propreidade Target  retorna um objeto que contém a referência à instância que você armazenou em WeakReference.

Nota: Você deve fazer um cast no objeto usando o operador 'as' ou fazer uma conversão explícita antes de usar a instância.

Executando a aplicação

Executando a aplicação teremos o seguinte resultado:

Antes de usar o recurso atente para o fato de que o comportamento do Garbage Collector é imprevisível e pode variar na execução.

Levando isso em conta você deve usar esse recurso com cautela.

(Disse Jesus) Não vos deixarei órfãos; voltarei para vós. João 14:18

Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

Referências:


José Carlos Macoratti