.NET - LINQ - Conceitos básicos e fundamentos - Expressões Lambda


O LINQ permite que você crie consultas a dados usando a sintaxe do seu código Visual Basic/C# independente da fonte de dados que você esta consultando: XML, memória , datataset, sistema, etc.; com isso você ganha produtividade pois você pode aplicar uma única sintaxe ao seu código. Usando expressões ao estilo SQL você pode selecionar, filtrar, ordenar, agrupar e agregar datasets.

Os operadores LINQ como Min, Max, Count , etc. podem reduzir drasticamente a quantidade de código para realizar as operações que usam estes tipos de funções.

Ao usar LINQ a sintaxe e o esquema é verificado em tempo de compilação evitando assim os erros em tempo de execução, runtime errors.

Vejamos a seguir mais um dos recursos que foram introduzidos para dar suporte ao LINQ.

O que são Expressões Lambda ?

As expressões lambda foram incluídas no VS/VB 2008 para dar suporte a consultas LINQ. As cláusulas Where são assim compiladas como expressões lambdas e chamadas em itens aplicáveis do seu dataset. Podem ser consideradas uma forma de delegate que pode passar ou retornar outra função.

Nota: Delegates permitem que uma classe use métodos de outra classe. Para saber mais sobre delegates leia o meu artigo: Usando Delegates

No LINQ as expressões lambda são usadas para realizar ações sobre listas de objetos e com extensões de métodos.

Uma expressão lambda é então uma função sem nome que calcula e retorna um valor único e podem ser usadas em qualquer lugar que um tipo delegate for válido.

Exemplos :

Function (numero As Integer) numero + 1 => Expressão lambda que aumenta o seu argumento e retorna um valor.

Function(n) n Mod 2 = 0 => Expressão lambda que verifica se um número é par.

Function(x) x ^ 3 => Expressão lambda que calcula o cubo de um número.

Mas como podemos usá-las no VB . NET ? Como chamar uma expressão lambda ?

Como uma expressão lambda é uma expressão ela somente pode ser usada como parte de uma instrução. Desta forma podemos declarar a expressão lambda e chamar a função passando um valor ao parâmetro:

Dim Cubo = Function(x) x ^ 3
Dim Incrementa = Function(numero As Integer) numero + 1
Dim ParOuImpar = Function(n) n Mod 2 = 0

Console.WriteLine(ParOuImpar(20))
Console.WriteLine(Incrementa(10))
Console.WriteLine(Cubo(5))


Retorno da execução:

True
11
125

No código acima temos 3 expressões lambdas declaradas que são usadas em seguida passando o valor do parâmetro esperado.

Como o Visual Basic pode inferir o tipo de cada variável podemos escrever um código mais enxuto.

Assim, uma expressão lambda pode ser retornada como um valor de uma chamada de função ou passada como um argumento para um parâmetro de um delegate.

Obs: O tipo delagate Func definido no namespace System pode passar até quatro parâmeetros e um tipo de retorno.

Func(Of T, TResult) - é um delegate que aceita um parâmetro integer e retorna um Boolean. Assim podemos usar

Dim Epar As Func(Of Integer, Boolean) = Function(n) n Mod 2 = 0

Console.WriteLine(EImpar(20))

No código acima o Delegate Epar é definido em uma linha de código e retorna um Boolean indicando se um inteiro passado como parâmetro é par(True) ou não(False).

Roteiro para criar uma expressão lambda:

Dentro de um método, em qualquer situação em que um tipo delegate pode ser usado, digite a palavra-chave Function, como no exemplo a seguir:

Dim valor = Function

Entre parênteses, diretamente após Function, digite os parâmetros da função. Observe que você não especifica um nome após Function.

Dim valor = Function (numero As Integer)

Após a lista de parâmetros, digite uma única expressão como corpo da função. O valor que a expressão processará é o valor retornado pela função. Você não usa uma cláusula As para especificar o tipo de retorno.

Dim valor = Function(numero As Integer)
numero + 1

As expressões Lambadas em consultas

No LINQ as expressões lambda são a base de muitos operadores usados nas consultas padrão. O compilador cria expressões lambda para capturar os cálculos definidos nos métodos fundamentais de consulta como Where, Select, Order By, Take While, e outros.

Exemplo: A consulta LINQ abaixo:

Dim clientes = From cli In db.Customers _
                     Where (cli.City = "Brazil") _
                     Select cli

é compilada assim :

Dim clientes = db.Customers _
                     .Where (Function(cli) cli.City="Brazil") _
                     .Select(Function(cli) cli)

Outros exemplos comparando com C# :

Retornar todos os produtos para uma determinada categoria
 C#  VB .NET

  
'instanciamos a classe DataContext que já 'tem mapeado os objetos e a conexão
  NorthwindDataContext db =  New NorthwindDataContext();

  return db.Products.Where( c => c.Category.CategoryName == Categoria).ToList;

 

'instanciamos a classe DataContext que já tem mapeado os objetos e a conexÆo
Dim db As New NorthwindDataContext

Return db.Products.Where(Function(c) c.Category.CategoryName = categoria)

 

Retornar um produto especifico para um codigo
 C#  VB .NET

  
'instanciamos a classe DataContext que já 'tem mapeado os objetos e a conexão
  NorthwindDataContext db =  New NorthwindDataContext();

  return db.Products.Single( p => p.ProductID == codigo);

 

'instanciamos a classe DataContext que já tem mapeado os objetos e a conexÆo
Dim db As New NorthwindDataContext

Return db.Products.Single(Function(p) p.ProductID = codigo)

 

A sintaxe das expressões lambdas

A sintaxe de uma expressão lambda lembra a de uma função padrão. As diferenças são as seguintes:

- Uma expressão lambda não tem um nome.

- Expressões lambda não podem ter modificadores, como
Overloads ou Overrides.

- Expressões lambda não usam uma cláusula As para designar o tipo de retorno da função. Em vez disso, o tipo é inferido do valor que o corpo da expressão lambda avalia. Por exemplo, se o corpo da expressão lamba for
Where cli.City = "Brazil", seu tipo de retorno é Boolean.

- O corpo da função deve ser uma expressão, não uma instrução. O corpo pode consistir de uma chamada para um procedimento de função, mas não uma chamada para um procedimento sub.

- Nas expressões lambadas não existe uma instrução
Return. O valor retornado pela função é o valor da expressão no corpo da função.

- Nas expressões lambdas não existe um instrução
End Function.

- Ou todos os parâmetros devem ter tipos de dados especificados ou todos devem ser inferidos.

- Parâmetros opcionais e
ParamArray não são permitidos.

- Parâmetros genéricos não são permitidos.

Como resultado dessas restrições e das maneiras pelas quais as expressões lambda são usadas, elas geralmente são simples , curtas e pouco complexas.

Uma expressão lambda compartilha seu contexto com o método no qual ela está definida. Ela tem os mesmos direitos de acesso que qualquer código escrito no método que a contém. Isso inclui acesso a variáveis de membro, funções e sub-rotinas, Me, e parâmetros e variáveis locais no método que a contém.

Podemos dizer que sem as expressões lambdas o LINQ não seria o mesmo.

Aguarde mais artigos sobre os fundamentos do LINQ. Até o próximo artigo...

Referências:

- Lambda Expressions - http://msdn.microsoft.com/en-us/library/bb531253.aspx


José Carlos Macoratti