csharp7-00

Embora em 2015 tenha acontecido o lançamento oficial do C# 6.0, no decorrer deste ano a Microsoft já vinha trabalhando na versão 7.0 desta linguagem. O estágio atual deste release já contempla algumas funcionalidades em fase de finalização, ao passo que outros recursos se encontram no estágio de especificação ou, até mesmo, prototipação.

O Build 2016 abordou algumas das funcionalidades esperadas para o C# 7.0, além de anunciar o Visual Studio “15” (nova versão do ambiente de desenvolvimento Microsoft). Maiores informações sobre o novo C# podem ser encontradas na seguinte página do projeto Roslyn:

https://github.com/dotnet/roslyn/blob/master/docs/Language%20Feature%20Status.md

Este artigo tem por objetivo apresentar um recurso chamado Pattern Matching, uma das diversas funcionalidades que integram o C# 7.0. Isto acontecerá através da implementação de um exemplo prático, empregando para isto o Visual Studio “15” como IDE.

Configurando o uso do C# 7.0 no Visual Studio “15”

Nos exemplos descritos neste artigo foi utilizado um projeto do tipo “Console Application” chamado ExemploPatternMaching. Esta aplicação de testes fará uso da versão 4.6.1 do .NET Framework, como indicado na Imagem 1:

csharp7-pattern-01
Imagem 1. Criando um projeto no Visual Studio “15”

Acessar na sequência a seção “Build”, dentro das propriedades do projeto ExemploPatternMaching. Incluir no campo “Conditional compilation symbols” os valores __DEMO__ e __DEMO_EXPERIMENTAL__, separando os mesmos por vírgula (Imagem 2):

csharp7-pattern-02
Imagem 2. Configurando o projeto para uso do C# 7.0

O valor __DEMO__ habilita o uso dos recursos do C# 7.0 (incluindo o mecanismo de Pattern Matching) em projetos criados a partir do Visual Studio “15”. Quanto a __DEMO_EXPERIMENTAL__, esta opção é específica para a utilização de Pattern Matching com a palavra-chave match (algo que será detalhado mais adiante).

Pattern Matching

Ao manipular objetos cujas classes derivam de um mesmo tipo básico é extremamente comum se recorrer a checagens empregando o operador is. Também são frequentes operações de “typecast” indicando o uso de uma estrutura requerida por um contexto específico.

Para exemplificar isto serão utilizadas as seguintes classes (Listagem 1):

  • Cotacao, tipo abstrato que representa uma cotação de moeda estrangeira;
  • CotacaoDolar, implementação concreta baseada em Cotacao e contendo informações da cotação do dólar norte-americano em uma data (tanto o valor comercial, quanto o correspondente para fins de turismo);
  • CotacaoEuro, com dados relativos a uma cotação do euro.
using System;

namespace ExemploPatternMatching
{
    public abstract class Cotacao
    {
        public DateTime DataCotacao { get; set; }
        public abstract string SiglaMoeda { get; }
        public abstract string NomeMoeda { get; }
    }

    public class CotacaoDolar : Cotacao
    {
        public override string SiglaMoeda
        { get { return "USD"; } }

        public override string NomeMoeda
        { get { return "Dólar norte-americano"; } }

        public double ValorComercial { get; set; }
        public double ValorTurismo { get; set; }
    }

    public class CotacaoEuro : Cotacao
    {
        public override string SiglaMoeda
        { get { return "EUR"; } }

        public override string NomeMoeda
        { get { return "Euro"; } }

        public double ValorCotacao { get; set; }
    }
}

Listagem 1: Exemplos de tipos para manipulação de cotações de moedas

Na Listagem 2 está a definição de um método chamado ExibirInformacoesCotacao:

  • Esta operação receberá como parâmetro uma instância do tipo Cotacao, a fim de exibir informações sobre uma moeda estrangeira;
  • Um único valor de cotação será mostrado. Para referências baseadas em CotacaoEuro este dado se encontra na propriedade ValorCotacao. Já para o tipo CotacaoDolar será assumido o valor associado à propriedade ValorComercial. Até o C# 6.0 todo este processo acontecia empregando o operador is, além de “casts” quando fosse necessário manipular implementações mais específicas da classe-base (Cotacao, no caso).
public static void ExibirInformacoesCotacao(Cotacao cotacao)
{
    double valorCotacao = 0;
    if (cotacao is CotacaoDolar)
    {
        valorCotacao =
            ((CotacaoDolar)cotacao).ValorComercial;
    }
    else if (cotacao is CotacaoEuro)
    {
        valorCotacao =
            ((CotacaoEuro)cotacao).ValorCotacao;
    }

    Console.WriteLine(new String('-', 40));
    Console.WriteLine($"Data: {cotacao.DataCotacao:dd/MM/yyyy}");
    Console.WriteLine($"Sigla: {cotacao.SiglaMoeda}");
    Console.WriteLine($"Moeda: {cotacao.NomeMoeda}");
    Console.WriteLine($"Valor: {valorCotacao:0.0000}");
}

Listagem 2: Método ExibirInformacoesCotacao

Na Listagem 3 é possível observar um exemplo de uso do recurso de Pattern Matching (após a refatoração do método ExibirInformacoesCotacao):

  • Esta funcionalidade permite definir uma variável em conjunto com o operador is, com a mesma sendo preenchida caso a referência em análise corresponda ao tipo que se está verificando;
  • A vantagem deste novo mecanismo está em eliminar a necessidade de codificação de um typecast, contribuindo assim para um código mais limpo e direto.
using System;

namespace ExemploPatternMatching
{
    class Program
    {
        public static void ExibirInformacoesCotacao(Cotacao cotacao)
        {
            double valorCotacao = 0;
            if (cotacao is CotacaoDolar dolar)
                valorCotacao = dolar.ValorComercial;
            else if (cotacao is CotacaoEuro euro)
                valorCotacao = euro.ValorCotacao;

            Console.WriteLine(new String('-', 40));
            Console.WriteLine($"Data: {cotacao.DataCotacao:dd/MM/yyyy}");
            Console.WriteLine($"Sigla: {cotacao.SiglaMoeda}");
            Console.WriteLine($"Moeda: {cotacao.NomeMoeda}");
            Console.WriteLine($"Valor: {valorCotacao:0.0000}");
        }

        static void Main(string[] args)
        {
            CotacaoDolar dolar = new CotacaoDolar();
            dolar.DataCotacao = new DateTime(2016, 4, 29);
            dolar.ValorComercial = 3.440;
            dolar.ValorTurismo = 3.580;
            ExibirInformacoesCotacao(dolar);

            CotacaoEuro euro = new CotacaoEuro();
            euro.DataCotacao = new DateTime(2016, 4, 29);
            euro.ValorCotacao = 3.938;
            ExibirInformacoesCotacao(euro);

            Console.ReadKey();
        }
    }
}

Listagem 3: Método ExibirInformacoesCotacao utilizando Pattern Matching

O resultado da execução deste bloco de código está na Imagem 3:

csharp7-pattern-03
Imagem 3. Executando o projeto ExemploPatternMaching

Conforme mencionado anteriormente, uma outra possibilidade de uso do mecanismo de Pattern Matching consiste em se empregar a palavra-chave match. É o que demonstra o trecho de código apresentado na Listagem 4:

  • Em cenários mais simples (como a atribuição de um valor a uma variável) a palavra-chave match é capaz de dispensar a presença de ifs validando uma referência;
  • As comparações acontecem a partir de cláusulas baseadas na palavra-chave case. A indicação com “*” será utilizada quando nenhuma das condições mais específicas for atendida.
public static void ExibirInformacoesCotacao(Cotacao cotacao)
{
    double valorCotacao = cotacao match
                          (
                              case CotacaoDolar dolar : dolar.ValorComercial
                              case CotacaoEuro euro : euro.ValorCotacao
                              case * : 0
                          );

    Console.WriteLine(new String('-', 40));
    Console.WriteLine($"Data: {cotacao.DataCotacao:dd/MM/yyyy}");
    Console.WriteLine($"Sigla: {cotacao.SiglaMoeda}");
    Console.WriteLine($"Moeda: {cotacao.NomeMoeda}");
    Console.WriteLine($"Valor: {valorCotacao:0.0000}");
}

Listagem 4: Método ExibirInformacoesCotacao utilizando a palavra-chave match

Conclusão

Este post representa o início de uma série que aborda as novas funcionalidades do C# 7.0, a partir de exemplos práticos que fazem uso do Visual Studio “15”. Em fase de definições e com alguns recursos disponíveis para testes, a tendência é que esta atualização do C# passe ainda por inúmeras mudanças ao longo do seu desenvolvimento. Assim como já aconteceu anteriormente com a versão 6.0, existe até mesmo a possibilidade de que algum mecanismo disponível neste momento (Abril/2016) deixe de fazer parte do release final.

Espero que este conteúdo possa ter sido útil.

Até uma próxima oportunidade!

Referências

The Future of C# – Build 2016
https://channel9.msdn.com/Events/Build/2016/B889

Renato Groffe

Atua como consultor em atividades voltadas ao desenvolvimento de softwares há mais de 13 anos. Bacharel em Sistemas de Informação, com especialização em Engenharia de Software. Microsoft Certified Technology Specialist (Web, WCF, Distributed Applications, ADO.NET, Windows Forms), Microsoft Specialist (HTML5 with JavaScript and CSS3, Developing ASP.NET MVC 4 Web Applications), Oracle Certified Associate (PL/SQL), Sun Certified (SCJP, SCWCD), ITIL Foundation V2, Cobit 4.1 Foundation.

Facebook Google+ 

Comentários

comentarios