Novas classes para inicialização de objetos

Quando desenvolvemos algum tipo de aplicação ou componente, é muito comum encontrarmos dentro do nosso código, classes que são extremamente custosas, ou melhor, que possuem um grande overhead na inicialização, como por exemplo, efetuam acesso à IO, cálculos complexos, etc. Dependendo da situação, instanciamos essas classes (pagando o alto preço da inicialização) e não utilizamos, já que, eventualmente, o teu sistema não precisará dela naquele momento.

Para melhorar isso, a Microsoft está disponibilizando no .NET Framework 4.0, uma classe genérica chamada Lazy<T> (namespace System). Basicamente, a finalidade desta classe é postergar, ao máximo, a criação do teu objeto, ou seja, isso somente acontecerá quando você realmente precisar dele. Por ser uma classe genérica e o parâmetro T não ter qualquer restrição, você pode definir T como qualquer tipo. Essa classe será um wrapper para o teu objeto custoso, efetuando a criação do mesmo somente quando for requisitado.

Ao instanciar a classe Lazy<T>, você tem algumas opções que variam de acordo com o overload do construtor que utiliza. Em um dos construtores, há um parâmetro boleano, que determina se a inicialização será ou não thread-safe. Se a instância da classe Lazy<T> pode ser acessada por um ambiente multi-threading, então definir este valor como True (que é o padrão), evitará problemas conhecidos, tal como as races conditions. Com isso, a primeira thread que entrar, incializará o objeto, e as threads subsequentes compartilharão o mesmo objeto, que já está criado. Mas se ambiente multi-threading não é o cenário, então definir esse parâmetro como False evitará processamentos extras, que são desnecessários neste caso.

Há também um overload do construtor, que recebe como parâmetro a instância de um delegate do tipo Func<T>. Esse delegate é referido como uma “factory”, ou seja, apontará para um método responsável por criar o objeto quando for solicitado, nos permitindo inicializá-lo de acordo com uma regra específica. Quando esse parâmetro não é informado, a classe Lazy<T> irá instanciar o tipo através do método CreateInstance da classe Activator, obrigando o tipo definido em T, a ter um construtor público sem parâmetros, caso contrário, uma exceção será disparada.

Além dos construtores, essa classe ainda expõe, publicamente, duas propriedades de somente leitura: IsValueCreated e Value. A primeira delas, retorna um valor boleano indicando se o objeto já foi ou não criado. Já a segunda, é a propriedade que utilizamos para extrair o objeto que foir criado e está sendo gerenciado pelo wrapper. É dentro desta propriedade que há toda a regra utilizada para determinar se o objeto já foi criado. E como vimos acima, caso ele ainda não tenha sido, invocará o método privado LazyInitValue, e me retornará a instância. Chamadas subsequentes, da mesma thread ou não, não entrarão mais neste método, reutilizando a instância criada. O código abaixo exibe um exemplo da utilização desta classe:

public class NotaFiscal
{
    public int Codigo { get; set; }
    public DateTime Data { get; set; }

    private Lazy<List<Item>> _itens;

    public NotaFiscal(int codigo)
    {
        this.Codigo = codigo;
        this._itens =
            new Lazy<List<Item>>(() => DataHelper.RecuperarItensDaNotaFiscal(this.Codigo));
    }

    public IEnumerable<Item> Itens
    {
        get
        {
            return this._itens.Value;
        }
    }
}

Como podemos perceber no código acima, a instância da classe representa uma Nota Fiscal. Muitas vezes carregamos a Nota Fiscal completa, incluindo seus respectivos itens, mas nem sempre eles são utilizados. Ao invés de carregar esses itens na criação da Nota Fiscal, iremos postergar essa tarefa, recorrendo a classe Lazy<T>. Como podemos ter vários itens, então o argumento T será definido como List<Item>. No construtor da classe Nota Fiscal, instanciamos a classe Lazy<List<Item>>, definindo em seu construtor, o método responsável por carregar os itens da Nota Fiscal. A propriedade que expõe os itens da Nota Fiscal, quando solicitada, recorre a propriedade Value do objeto _itens, que como vimos acima, é neste momento que o método (factoryRecuperarItensDaNotaFiscal será disparado.

Além da classe Lazy<T>, ainda temos a classe ThreadLocal<T> (namespace System.Threading). Assim como a anterior, não há nenhuma restrição quanto ao argumento T, ou seja, podemos definir qualquer tipo. A finalidade desta classe, é sanar alguns comportamentos de campos estáticos quando utilizados em conjuto com o atributo ThreadStaticAttribute. Ao aplicar esse atributo, cada thread terá a sua própria cópia do valor, mesmo que ele seja declarado como estático (static). O problema que ocorre ao utilizar esse atributo, é quando temos um campo que já é automaticamente inicializado, como por exemplo:

public class Teste
{
    [ThreadStatic]
    public static int Numero = 4;
}

A inicialização de todo membro estático ocorre apenas uma única vez, mesmo quando temos este atributo aplicado. Para ilustrar isso, vamos criar três threads diferentes, onde cada uma delas escreverá o valor do membro Numero:

new Thread(() => Console.WriteLine(Teste.Numero)).Start();
new Thread(() => Console.WriteLine(Teste.Numero)).Start();
new Thread(() => Console.WriteLine(Teste.Numero)).Start();

E o resultado é: 4, 0 e 0. A classe ThreadLocal<T> vai conseguir lidar com isso, ou seja, permitirá especificar um delegate de inicialização, que será invocado sempre que o valor for requisitado por uma nova thread. Ao invés da inicialização acontecer uma única vez, ele sempre rodará quando solicitado, e sempre trazendo a cópia da informação para dentro da thread corrente, não compartilhando o mesmo, assim como já acontecia anteriormente. Com essa nova classe, podemos reescrever o exemplo da seguinte forma:

public class Teste
{
    public static ThreadLocal<int> Numero = new ThreadLocal<int>(() => 4);
}

new Thread(() => Console.WriteLine(Teste.Numero.Value)).Start();
new Thread(() => Console.WriteLine(Teste.Numero.Value)).Start();
new Thread(() => Console.WriteLine(Teste.Numero.Value)).Start();

E agora, como já era de se esperar, temos como resultado: 4, 4 e 4. É importante dizer que se nada for informado no construtor desta classe, ela sempre construirá o tipo com o seu valor padrão.

Para finalizar, temos a classe estática LazyInitializer, que possui apenas um único método público: EnsureInitialized. Neste caso, ao invés de definir todos os membros como Lazy<T>, podemos recorrer a este método para inicializá-los individualmente, quando você achar necessário, sem a necessidade do wrapper. O código abaixo ilustra a utilização desta técnica, mas repare que informamos o objeto que será abastecido e o método (factory) que o construirá.

public IEnumerable<Item> Itens
{
    get
    {
        if (this._itens == null)
            LazyInitializer.EnsureInitialized(ref _itens, () => DataHelper.RecuperarItensDaNotaFiscal(this.Codigo));

        return this._itens;
    }
}

Conclusão: Criar aplicações multi-threading é bem simples, mas o grande problema sempre é a sincronização delas. Classes como essas que vimos aqui, auxilia bastante neste caso, tirando em algum pontos, a responsabilidade do usuário em gerenciar isso, podendo ele se preocupar cada vez mais com as regras de negócio. Essas classes que vimos aqui, estarão disponíveis a partir da versão 4.0 do .NET Framework, que já trará também uma grande API para suportar o desenvolvimento de código paralelo.

Publicidade

Persistência da linha selecionada

Quando temos a paginação e a seleção no GridView habilitadas, há um comportamento estranho. Ao selecionar uma linha em um GridView paginado, o ASP.NET armazena o índice da linha selecionada, e ao mudar de página, a mesma linha (porém outro registro) fica também marcada, e isso muitas vezes gera uma confusão.

Na versão 4.0 do ASP.NET, a Microsoft está adicionando uma propriedade boleana no GridView chamada EnablePersistedSelection. Ao definir como True, ele armazenará as datakeys ao invés do índice da linha no GridView, e com isso, ao mudar de página, nenhuma linha é marcada como selecionada, o que faz mais sentido. Ao voltar para a página que possui aquele registro, conseguimos visualizá-lo como marcado. Por padrão, essa propriedade é definida como False para efeitos de compatibilidade com as versões anteriores.

Ativação do host baseando-se na memória

O WCF fornece uma opção que nos permite configurar a porcentagem mínima de memória disponível na máquina antes de ativar o serviço. Para customizar isso, recorremos a propriedade (atributo) MinFreeMemoryPercentageToActivateService da classe (elemento) ServiceHostingEnvironmentSection. Essa propriedade recebe um número inteiro, que corresponde a quantidade de memória disponível que a máquina onde o serviço está rodando deverá ter disponível.

Como essa configuração recorre a métodos não gerenciados para fazer essa verificação, a aplicação (serviço) deverá estar rodando em full-trust. Caso contrário, uma exceção do tipo SecurityException será disparada e, consequentemente, o serviço não estará disponível para receber requisições.

Novos métodos para Enumeradores

A partir da versão 4.0 do .NET Framework, teremos dois novos métodos estáticos para a manipulação de enumeradores fornecidos pela classe Enum: TryParse<TEnum> e HasFlag.

Como podemos perceber, o primeiro deles, TryParse<TEnum>, trata-se de um método genérico, que recebe dois parâmetros. O primeiro deles, é uma string contendo o nome ou valor do item a ser pesquisado dentro do enumerador, já informado pelo argumento genérico TEnum; já o segundo parâmetro (de saída), é do tipo TEnum, pois caso a conversão seja possível, esse resultado já traz a informação tipada. E ainda, este método retorna um valor boleano, indicando se a conversão foi ou não possível, ao contrário do método Parse, que dispara uma exceção. Esse método trabalha de forma semalhante ao método TryParse das estruturas DateTime, Int32, entre outras que já fazem parte do .NET Framework. Abaixo temos o exemplo da sua utilização:

public enum Itens { Read, Write, FullControl, None }

Itens permissoes = Itens.None;

if (Enum.TryParse<Itens>(“Read”, out temp).ToString())
    Console.WriteLine(“Nível de Permissão: {0}”, temp);
else
    Console.WriteLine(“Não foi possível determinar o tipo de Permissão.”);

Além desse método, a Microsoft também está adicionando o método de instância chamado HasFlag, que retorna uma valor boleano indicando se o valor existe ou não dentro daquele enumerador. Com ele, a partir da variável que armazena o(s) enumerador(es) selecionado(s), podemos invocá-lo e passarmos o item a ser verificado, assim como podemos reparar no exemplo abaixo:

Itens permissoes = Itens.Read | Itens.Write;

if (permissoes.HasFlag(Itens.FullControl))
    Console.WriteLine(“Você tem permissão total.”);

Copiando Streams

Uma operação muito comum é a cópia de streams. Há diversas situações onde você pode querer usar isso, como por exemplo, armazenar um conteúdo de um arquivo em memória, para não precisar acessar o arquivo físico toda vez que precisar dele. Antes do .NET Framework 4.0, com o stream de origem em mãos, precisávamos armazenar os blocos em um buffer temporário, e em seguida, copiar para o stream de destino.

Apesar de não ser uma tarefa muito difícil de fazer, ela é propícia a erros, já que você precisa ficar manipulando índices para invocar os métodos Read e Write. Com o .NET Framework 4.0, a Microsoft acaba de adicionar um método (de instância) chamado CopyTo na classe Stream. Com ele, todas as classes que derivam direta ou indiretamente dela, poderão copiar o conteúdo atual para um outro Stream. Tudo o que precisamos fazer é:

MemoryStream ms = new MemoryStream();

using (FileStream fs = File.Open(“Arquivo.xml”, FileMode.Open)
    fs.CopyTo(ms);