C# - O operador lambda (=>)


 Hoje vamos recordar conceitos sobre o operador lambda (=>) usado na linguagem C#.

Na linguagem C#, o token => é suportado em duas formas :

  1. Como o operador lambda;
  2. Como um separador do nome do membro e da sua implementação em uma definição de corpo de expressão;

Neste artigo vamos focar no operador lambda, onde o token => é um operador retirado de linguagens funcionais que pode tornar o código mais curto e limpo mas pode tornar a sintaxe difícil de entender especialmente se você nunca usou uma linguagem funcional antes.

Onde quer que possamos usar um delegate, também podemos usar uma expressão lambda, onde o operador lambda é usado, que é uma função anônima que pode conter expressões e instruções.

No lado esquerdo do operador, temos um grupo de dados e, no lado direito, uma expressão ou um bloco de declarações. Essas instruções são aplicadas em cada item dos dados.

Nas expressões lambda, não temos uma palavra-chave de retorno. A última instrução é retornada automaticamente, e  não precisamos especificar tipos para nossos parâmetros. O compilador vai adivinha o tipo de parâmetro correto fazendo o que é chamado de inferência de tipo.

Para criar uma expressão lambda, temos que especificar os parâmetros de entrada (se houver) no lado esquerdo do operador lambda => e colocar a expressão ou o bloco de instruções do outro lado.

Por exemplo, a expressão lambda x => x * x especifica um parâmetro chamado x e retorna o valor de x ao quadrado.

A expressão usada é chamada de corpo da expressão e possui a seguinte sintaxe geral:

 

   membro => expressao;

 

Aqui o operador lambda (=>) divide a expressão lambda em duas partes :

  1. O lado esquerdo que o parâmetro de entrada
  2. O lado direito que é o corpo da expressão

onde :

expressão é uma expressão válida. O tipo de retorno da expressão deve ser implicitamente conversível no tipo de retorno do membro. Se o tipo de retorno do membro for nulo ou se o membro for um construtor, finalizador ou acessador de conjunto de propriedades, a expressão deverá ser uma expressão de instrução, que pode ser de qualquer tipo.

No exemplo a seguir temos a definição de um corpo de expressão para o método ToString() de um tipo Pessoa que foi definido previamente :

 
   public override string ToString() => $"{nome} {sobrenome}".Trim();

 

A seguir temos um exemplo clássico do operador => usado o LINQ:

       static void Main(string[] args)
        {
            string[] palavras = { "casa", "banana", "carro" };

            int menorPalavra = palavras
                           .Where(p => p.StartsWith("a"))
                           .Min(p => p.Length);
            Console.WriteLine(menorPalavra);   
            Console.ReadLine();
        }

Os parâmetros de entrada usados na expressão lambda são fortemente tipados em tempo de compilação, e, quando o compilador infere os tipos destes parâmetros, como no exemplo acima, podemos omitir as declarações de tipo.

A seguir temos outro exemplo clássico, onde temos uma lista de números inteiros e estamos exibindo no console os números maiores que 3 :

      static void Main(string[] args)
        {
            var lista = new List<int>() { 3, 2, 1, 8, 6, 4, 7, 9, 5 };
            var subLista = lista.FindAll(val => val > 3);
            foreach (int i in subLista)
            {
                Console.WriteLine(i);
            }
            Console.ReadLine();
        }

Neste código usamos o operador lambda (=>) junto com o método FindAll() que usa um predicado como parâmetro.

Assim neste código temos que :

- Um predicado é um tipo especial de delegate que retorna um valor booleano sendo aplicado a todos os itens da lista;

- val é um parâmetro de entrada especificado sem um tipo. (Poderíamos especificar explicitamente o tipo, mas não é necessário pois compilador vai inferir o tipo e vai esperar um tipo int.)

- val que é um valor de entrada atual da lista, é então comparado para ver se é maior que 3, onde um booleano true ou false será retornado.  Se a expressão (val > 3) for true o valor é retornado e acrescido a coleção subLista;

- Finalmente, o método FindAll() vai retornar todos os valores que atenderam à condição (val > 3), sendo atribuídos à coleção subLista;

- Ao final a coleção subLista é percorrida usando um foreach e cada número é exibido;

E estamos conversados.

(Disse Jesus)"Eu sou a videira verdadeira, e meu Pai é o lavrador. Toda a vara em mim, que não dá fruto, a tira; e limpa toda aquela que dá fruto, para que dê mais fruto."
João 15:1,2

Referências:


José Carlos Macoratti