C#

C# 9.0 - Programas top-level e Pattern Matching

Dando continuidade ao nosso estudo do C# 9.0, neste artigo veremos dois novos recursos dele: Programas top-leve e Pattern Matching.

há 3 anos 3 meses

Formação Desenvolvedor C#
Conheça a formação em detalhes

Dando continuidade a nossa série de posts sobre os novos recursos do C# 9.0. No artigo passado vimos as propriedades init e records (registros) e agora conheceremos mais dois: programas top-level e as melhorias do pattern matching.

Programas Top-level

Antes da versão 9.0, para escrever qualquer código no C# era necessário declarar ao menos uma classe, com um método Main estático. Como no famoso “Hello World” abaixo:

using System;
class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Hello World");
    }
}

Quem nunca viu um código na vida, pode ter dificuldade em compreender todos os conceitos utilizados no código acima. Para ajudar nisso, no C# 9.0 foi introduzido os programas top-level, que não necessitam de classe nem do método Main para serem executados.

Com os programas top-level, o famoso “Hello World” pode ser definido da seguinte forma:

using System;

Console.WriteLine("Hello World");

Qualquer expressão válida do C# pode ser declarada em um programa top-level, com a limitação que isso só pode ser definido em um arquivo de código. Mesmo que o programa declare uma função:

using System;

int Soma(int var1, int var2) {
  return var1 + var2;
}

Console.WriteLine(Soma(10, 20));

Ela só pode ser utilizada dentro do arquivo onde foi criada. Será gerado um erro se for invocada fora dele.

Também é importante ressaltar que os usings sempre devem ser as instruções iniciais do código. Caso estiverem no meio dele, será gerado um erro.

Por fim, os programas top-level definem a variável global args, que contém os argumentos passados via linha de comando e podem retornar um valor para o sistema operacional:

using static System.Console;

WriteLine(args[0]);

return 0;

O valor retornado indica se o programa finalizou com sucesso ou não. Lembrando que qualquer valor diferente de zero indica que o programa foi finalizado devido a um erro.

Melhorias no pattern matching

O pattern matching foi introduzido no C# 7.0 como uma forma de facilitar a verificação do tipo de dado de uma variável. Na versão 8.0, com a introdução das Switch Expressions este recurso recebeu suas primeiras melhorias e agora na nona versão, novos recursos foram incorporados ao padrão.

Antes, quando o pattern matching é aplicado em uma switch expression:

public double CustoObra(object item) 
{
    return item switch
    {
        Formato t when t.Area < 100 => Area * 1.8,
        Formato t when t.Area > 200 => Area * 1.5,
        Formato _ => Area * 2.0,
    };
}

Era necessário informar um identificador, mesmo que fosse descartado (_), agora isso não é necessário:

public double CustoObra(object item) 
{
    return item switch
    {
        Formato t when t.Area < 100 => Area * 1.8,
        Formato t when t.Area > 200 => Area * 1.5,
        Formato => Area * 2.0,
    };
}

Quando se está aplicando condições a mesma propriedade como no exemplo acima, podemos utilizar o relational pattern e utilizar apenas os condicionais no switch:

public double CustoObra(Formato item) 
  => Formato t when t.Area switch
  	{
        < 100 => Area * 1.8,
        > 200 => Area * 1.5,
        _ => Area * 2.0,
    };

Que também pode receber os operadores lógicos or, and e not:

public double CustoObra(Formato item) 
  => Formato t when t.Area switch
  	{
        > 0 and <= 100 => Area * 1.8,
        > 100 and <= 200 => Area * 1.6,
        > 200 => Area * 1.5,
        _ => Area * 2.0,
    };

Sempre que possível, opte pelo operador not, em detrimento de !, já que o primeiro melhora a legibilidade do código. Ele pode ser utilizado para verificar se um valor não é nulo:

public Formato SelecionarFormato(object item) 
		=> item switch
    {
        FormatoPlanta.Quadrado => new Quadrado(Largura, Altura),
        FormatoPlanta.Retangulo => new Retangulo(Largura, Altura),
        FormatoPlanta.Triangulo => new Triangulo(Largura, Altura, 2),
        not null => throw new ArgumentException("Formato desconhecido"),
        null => throw new ArgumentNullException(nameof(item))
    };

Ou mesmo para analisar o tipo de uma variável:

if (item is not FormatoPlanta) { throw ... }

Ao aplicar um condicional como o acima, o C# saberá o tipo da variável, então o compilador aceita algo assim:

if (item is not FormatoPlanta) { throw ... }
var = item.Area ...

Com isso finalizamos mais um artigo sobre o C# 9.0. No próximo abordarei outros recursos desta nova versão da linguagem. Até lá!

Autor(a) do artigo

Wladimilson M. Nascimento
Wladimilson M. Nascimento

Instrutor, nerd, cinéfilo e desenvolvedor nas horas vagas. Graduado em Ciências da Computação pela Universidade Metodista de São Paulo.

Todos os artigos

Artigos relacionados Ver todos