Desenvolvimento

22 ago, 2016

C# – Usando expressões regulares compiladas

Publicidade

Neste artigo, vou mostrar como podemos minimizar o impacto no desempenho de uma aplicação que surge quando precisamos usar expressões regulares com frequência.

Por padrão, quando você cria um objeto Regex, o padrão da expressão regular especificado no construtor é compilado para uma forma intermediária (não MSIL). Então, cada vez que você usar o objeto Regex, o runtime interpreta a forma intermediária do padrão e o aplica para a sequência alvo.

Com expressões regulares complexas que são usadas com frequência, esse processo de interpretação repetido pode ter um efeito negativo sobre o desempenho do seu aplicativo.

Ao especificar a opção RegexOptions.Compiled, quando você cria um objeto Regex, você força o runtime .NET a compilar a expressão regular para a MSIL em vez de usar uma forma intermediária interpretada.

Esse MSIL é compilado just-in-time (JIT) pelo runtime para um assembly nativo na primeira execução, assim como um assembly regular. Você então usa uma expressão regular compilada da mesma maneira como você usa qualquer objeto Regex; a compilação simplesmente resulta em uma execução mais rápida.

No entanto, existem alguns efeitos colaterais nesse procedimento:

  • Em primeiro lugar, o compilador JIT tem que fazer mais trabalho, que irá introduzir atrasos durante a compilação JIT. Isso é mais perceptível se você criar as suas expressões regulares compiladas quando o seu aplicativo for iniciado;
  • Em segundo lugar, o runtime não consegue descarregar uma expressão regular compilada depois de ter terminado o processamento;
  • Ao contrário de uma expressão regular normal, o coletor de lixo não irá recuperar a memória usada pela expressão regular compilada. A expressão regular compilada permanecerá na memória até que o seu programa termine ou você descarregue o domínio do aplicativo em que a expressão regular compilada é carregada.

O método estático Regex.CompileToAssembly permite que você crie uma expressão regular compilada e a grave em um assembly externo.  Isso significa que você pode criar assemblies contendo conjuntos de expressões regulares, que você pode usar a partir de múltiplas aplicações. Para compilar uma expressão regular persistindo-a para um assembly, basta seguir os procedimentos que iremos descrever a seguir.

Compilando um Regex para um Assembly

A seguir, temos as etapas para compilar um Regex para um assembly:

  • Crie uma matriz do tipo System.Text.RegularExpressions.RegexCompilationInfo grande o suficiente para conter um objeto RegexCompilationInfo para cada uma das expressões regulares compiladas que você deseja criar.
  • Crie um objeto RegexCompilationInfo para cada uma das expressões regulares compiladas. Especifique valores para as suas propriedades como argumentos para o objeto construtor. A seguir estão as propriedades mais utilizadas:
  1. IsPublic, um valor booleano que especifica se a expressão regular gerada tem visibilidade pública;
  2. Name, um valor String que especifica o nome da classe;
  3. Namespace, um valor String que especifica o namespace da classe;
  4. Pattern, um valor String que especifica o padrão que a expressão regular irá corresponder;
  5. Options, um valor do tipo System.Text.RegularExpressions.RegexOptions que especifica opções para a expressão regular.
  • Crie um objeto do tipo System.Reflection.AssemblyName e configure-o para representar o nome do assembly que o método Regex.CompileToAssembly irá criar;
  • Execute o Regex.CompileToAssembly passando o array RegexCompilationInfo e o objeto AssemblyName.

Esse processo cria uma assembly que contém uma declaração de classe para cada expressão regular compilada em que cada classe deriva de Regex. Para usar a expressão regular compilada contida no assembly, basta instanciar a expressão regular que você deseja usar e chamar o método como se você tivesse simplesmente criado com o construtor Regex normal.

Neste artigo eu vou mostrar um exemplo de como criar um objeto Regex que é compilado para o MSIL em vez da forma intermediária usual.

Recursos usados:

Criando o projeto no VS Community

Abra o VS Community 2015  e clique em New Project.

A seguir, selecione Visual C# -> Console Application.

Informe o nome Regex_MSIL e clique no botão OK.

c_cregex-1

Em seguida, defina o seguinte código no método Main() da classe Program.cs:

using System;
using System.Reflection;
using System.Text.RegularExpressions;

namespace Regex_MSIL
{
    class Program
    {
        static void Main(string[] args)
        {
            string mensagem = null;

            Console.WriteLine("Criando dois objetos Regex Compilados: PinRegex e CartaoCreditoRegex.");
            Console.WriteLine("Processando...");
            Console.WriteLine("");
            try
            {
                // Cria um array para tratar as informações do objeto Regex (definimos um array com tamanho 2)
                RegexCompilationInfo[] regexInfo = new RegexCompilationInfo[2];

                // Cria o RegexCompilationInfo para a expressão PinRegex
                regexInfo[0] = new RegexCompilationInfo(@"^\d{4}quot;, RegexOptions.Compiled, "PinRegex", "", true);

                // Cria o RegexCompilationInfo para o objeto CartaoCreditoRegex.
                regexInfo[1] = new RegexCompilationInfo(@"^\d{4}-?\d{4}-?\d{4}-?\d{4}quot;, RegexOptions.Compiled, "CartaoCreditoRegex", "", true);

                // Cria um AssemblyName  para definir um assembly de destino.
                AssemblyName assembly = new AssemblyName();
                assembly.Name = "MacorattiRegEx";

                // Cria a expressão regular compilada
                Regex.CompileToAssembly(regexInfo, assembly);
                mensagem = "Os objetos Regex - PinRegex e CartaoCreditoRegex - foram criados e compilados com sucesso ";
            }
            catch (Exception ex)
            {
                mensagem = ex.Message;
            }

            Console.WriteLine(mensagem);
            Console.ReadKey();
        }
    }
}

Esse código irá criar o arquivo MacorattiRegEx.dll contendo as nossas expressões regulares – CartaoCreditoRegex e PinRegex – compiladas.

Executando o projeto, iremos obter o resultado exibido a seguir:

c_cregex-2

Pegue o projeto completo aqui: Regex_MSIL.zip.