Dissecando as expressões Lambda

C#

Esta semana fui questionado sobre o que singificava aquele “treco” que todo mundo usa quando vai fazer uma consulta linq. São as expressões lambda, eu disse. Acabei percebendo que na turma ninguém sabia o que eram expressões lambda, apesar de todos as utilizarem.

O primeiro passo para entendermos as expressões lambda é desvendar sua origem. Nosso estudo deve, portanto, se iniciar pelos delegates...

O conceito de delegates não é algo tão novo. O pessoal mais nostalgico vai se animar com este assunto. Este conceito já era utilizado no na linguagem C e era intitulado "ponteiro para função". Terminologia que deixa mais claro o que um delegate realmente faz.

O delegate assim como o ponteiro para função, guarda uma referência a uma função(ou método) e permite que chamemos essa função quando precisarmos.

Em .Net estes "ponteiros" foram entitulados delegates e adicionou-se segurança de tipo a ele, sendo assim, para utilizar um delegate devemos especificar exatamente o tipo do resultado que o método apontado retorna, bem como os argumentos que o método espera receber.

Após satisfazer estas condições podemos "passar" o delegate como se fosse uma variável.

Nosso primeiro exemplo mostra o uso de delegate assim como era utilizado no .NET 1.0! Definimos um delegate e o tipo de argumento para o mesmo. Criamos o delegate e apontamos para o método de referência. Agora podemos
utilizar nosso delegate pelo código...

Lambda1

Dando um salto até o lançamento do .NET 2.0, teremos uma nova feature que irá facilitar o uso dos delegates em relação a maneira como eram escritos anteriormente. Este novo recurso eram os "Métodos Anônimos".

Os métodos anônimos suprimem a necessidade de se criar outros métodos para apontá-los com delegates!!! É isso mesmo! Agora podemos definir o método a ser apontado no mesmo instante em que criamos o delegate e o compilador fica com a responsabilidade da interpretação. Na prática houve aqui um grande evolução na escrita do código.

Vamos observar o funcionamento de um delegate tradicional comparado a sua utilização com um método anônimo:

2

Podemos ver claramente a diferença aqui. Com os métodos anônimos, não precisamos criar outro método e um delegate que aponta para esse método. Dizemos apenas que queremos um delegate aqui e especificamos o corpo do método a ser chamado. É muito mais conveniente utilizar um método anônimo ao invés do modo com delegate tradicional. A definição do código a utilizar fica junto a sua utilização, tornando tudo mais intelegível.

Outra característica introduzida com os métodos anônimos é a possibilidade de usar variáveis definidas fora do método anônimo: Utilizando o exemplo acima, podemos ter uma variável e a utilizar na condição do método anônimo.

3

Neste exemplo vemos o uso da variável "procuraValor" dentro corpo do método do delegate embora tenhamos o definido fora dele. Neste caso, o compilador C# não somente cria o método como a própria classe (que contém o método) onde o valor que usaremos no corpo do delegate é passado como um membro dessa classe.

Expressões Lambda

Lambda expressions são expressões anônimas e métodos anônimos com uma sintaxe açucarada(syntatic sugar ou açucar sintático refere-se a maior legibilidade do código bem como maior facilidade na escrita) que tornará mais agradavel e elegante a forma de embarcar métodos anônimos ao código.

Nos dias de hoje, no C#3.0 (e no .NET 3.5) temos as expressões Lambda que são o próximo passo na "evolução do delegate". Agora, o compilador faz sumir o "delegate(...) {...}" (isso economiza um monte de digitação). Uma expressão lambda sempre consiste de duas partes (esquerda e direita) separadas por um "=>". Este(=>) por sua vez é o operador lambda que foi introduzido no C# 3.0 e é lido como "goes to" (vai para). A parte à esquerda do operador labmda contém uma lista de argumentos(não necessariamente tipados pois os tipos  podem ser automáticamente indicados pelo compilador) a serem passados ao método. O lado direito contém o corpo do método.

Vamos a prática:

Em um determinado cenário temos um conjunto de regras que são alteradas com frequência. Para um melhor desing decidimos isolar este trecho de código. Criamos então um delegate que retorna um double. Em nossa aplicação percorremos uma lista de valores e aplicamos para cada item nossa regra, que em suma aplica o valor 0.0 quando o resultado retornado for menor que 300.00.

4

Notem que a expressão Lambda utilizada no método AplicaRegras é iniciado por um argumento de tipo implícito (i) que vai para o resultado de um calculo que neste caso e 15% do item em questão.

Agora fica muito mais fácil entender nossas consultas linq…

    
// Crio um objeto de contexto
ContextoDeDados contexto = new ContextoDeDados();
// Consulto os desenvolvedores que trabalhama na empresa Literatura e Cia
var consulta = contexto.desenvolvedores.Where(c => c.Empresa == "Literatura e Cia");
    
Baixe o código dos Exemplos utilizados neste artigo.

Author's profile picture

Vitor is a computer scientist who is passionate about creating software that will positively change the world we live in.

MVP Azure - Cloud Architect - Data science enthusiast


4 minutes to read