LINQ - Expressões Lambda

O termo 'expressão lambda' deriva seu nome de cálculo 'lambda', que por sua vez é uma notação matemática aplicada para definir funções. As expressões lambda como parte executável de uma equação LINQ traduzem a lógica de uma maneira em tempo de execução para que ela possa passar para a fonte de dados convenientemente. No entanto, as expressões lambda não se limitam apenas a localizar aplicativos no LINQ apenas.

Essas expressões são expressas pela seguinte sintaxe -

(Input parameters) ⇒ Expression or statement block

Aqui está um exemplo de uma expressão lambda -

y ⇒ y * y

A expressão acima especifica um parâmetro denominado y e o valor de y é elevado ao quadrado. No entanto, não é possível executar uma expressão lambda neste formato. Exemplo de uma expressão lambda em C # é mostrado abaixo.

C #

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace lambdaexample {
   class Program {

      delegate int del(int i);
      static void Main(string[] args) {

         del myDelegate = y ⇒ y * y;
         int j = myDelegate(5);
         Console.WriteLine(j);
         Console.ReadLine();
      }
   }
}

VB

Module Module1
   Private Delegate Function del(ByVal i As Integer) As Integer
   
   Sub Main(ByVal args As String())
   
      Dim myDelegate As del = Function(y) y * y
      Dim j As Integer = myDelegate(5)
      Console.WriteLine(j)
      Console.ReadLine()
	  
   End Sub
   
End Module

Quando o código acima de C # ou VB é compilado e executado, ele produz o seguinte resultado -

25

Expression Lambda

Como a expressão na sintaxe da expressão lambda mostrada acima está no lado direito, elas também são conhecidas como expressão lambda.

Lambdas assíncronos

A expressão lambda criada pela incorporação do processamento assíncrono pelo uso da palavra-chave async é conhecida como lambdas assíncronas. Abaixo está um exemplo de lambda assíncrono.

Func<Task<string>> getWordAsync = async()⇒ “hello”;

Lambda em operadores de consulta padrão

Uma expressão lambda dentro de um operador de consulta é avaliada pelo mesmo sob demanda e trabalha continuamente em cada um dos elementos na seqüência de entrada e não em toda a seqüência. Os desenvolvedores podem usar a expressão Lambda para alimentar sua própria lógica nos operadores de consulta padrão. No exemplo a seguir, o desenvolvedor usou o operador 'Onde' para recuperar os valores ímpares de uma determinada lista, usando uma expressão lambda.

C #

//Get the average of the odd Fibonacci numbers in the series... 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace lambdaexample {
   class Program {     
      static void Main(string[] args) {
      
         int[] fibNum = { 1, 1, 2, 3, 5, 8, 13, 21, 34 };
         double averageValue = fibNum.Where(num ⇒ num % 2 == 1).Average();
         Console.WriteLine(averageValue);
         Console.ReadLine();
      }
   }
}

VB

Module Module1

   Sub Main()
   
      Dim fibNum As Integer() = {1, 1, 2, 3, 5, 8, 13, 21, 34}
      Dim averageValue As Double = fibNum.Where(Function(num) num Mod 2 = 1).Average()
	  
      Console.WriteLine(averageValue)
      Console.ReadLine()
	  
   End Sub
   
End Module

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

7.33333333333333

Digite inferência em Lambda

Em C #, a inferência de tipo é usada convenientemente em uma variedade de situações e também sem especificar os tipos explicitamente. No entanto, no caso de uma expressão lambda, a inferência de tipo funcionará apenas quando cada tipo tiver sido especificado, pois o compilador deve ser satisfeito. Vamos considerar o seguinte exemplo.

delegate int Transformer (int i);

Aqui, o compilador emprega a inferência de tipo para se basear no fato de que x é um inteiro e isso é feito examinando o tipo de parâmetro do Transformer.

Escopo Variável na Expressão Lambda

Existem algumas regras ao usar o escopo de variável em uma expressão lambda, como variáveis ​​iniciadas em uma expressão lambda que não devem ser visíveis em um método externo. Também existe uma regra de que uma variável capturada não deve ser coletada como lixo, a menos que o delegado que faz referência à mesma se torne elegível para o ato de coleta de lixo. Além disso, existe uma regra que proíbe uma instrução de retorno dentro de uma expressão lambda para causar o retorno de um método envolvente.

Aqui está um exemplo para demonstrar o escopo da variável na expressão lambda.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace lambdaexample {
   class Program {
      delegate bool D();
      delegate bool D2(int i);

      class Test {
         D del;
         D2 del2;
			
         public void TestMethod(int input) {
            int j = 0;
            // Initialize the delegates with lambda expressions.
            // Note access to 2 outer variables.
            // del will be invoked within this method.
            del = () ⇒ { j = 10; return j > input; };

            // del2 will be invoked after TestMethod goes out of scope.
            del2 = (x) ⇒ { return x == j; };

            // Demonstrate value of j:            
            // The delegate has not been invoked yet.
            Console.WriteLine("j = {0}", j);        // Invoke the delegate.
            bool boolResult = del();
           
            Console.WriteLine("j = {0}. b = {1}", j, boolResult);
         }

         static void Main() {
            Test test = new Test();
            test.TestMethod(5);

            // Prove that del2 still has a copy of
            // local variable j from TestMethod.
            bool result = test.del2(10);
           
            Console.WriteLine(result);

            Console.ReadKey();
         }
      }
   }
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

j = 0
j = 10. b = True
True

Árvore de Expressão

Expressões lambda são usadas em Expression Treeconstrução extensivamente. Uma árvore de expressão fornece código em uma estrutura de dados semelhante a uma árvore em que cada nó é uma expressão como uma chamada de método ou pode ser uma operação binária como x <y. Abaixo está um exemplo de uso da expressão lambda para construir uma árvore de expressão.

Declaração Lambda

Também há statement lambdasconsistindo em duas ou três declarações, mas não são usadas na construção de árvores de expressão. Uma instrução de retorno deve ser escrita em uma instrução lambda.

Sintaxe da instrução lambda

(params)⇒ {statements}

Exemplo de uma declaração lambda

using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace lambdaexample {
   class Program {
      static void Main(string[] args) {
         int[] source = new[] { 3, 8, 4, 6, 1, 7, 9, 2, 4, 8 };

         foreach (int i in source.Where(x ⇒ 
            {
               if (x <= 3)
                  return true;
               else if (x >= 7)
                  return true;
               return false;
            }
         ))
        Console.WriteLine(i);
        Console.ReadLine();
      }
   }
}

Quando o código acima é compilado e executado, ele produz o seguinte resultado -

3
8
1
7
9
2
8

Lambdas são empregados como argumentos em consultas LINQ com base em métodos e nunca podem ter um lugar no lado esquerdo de operadores como is ou asapenas como métodos anônimos. Embora as expressões Lambda sejam muito semelhantes aos métodos anônimos, eles não são restritos ao uso apenas como delegados.

Pontos a serem lembrados ao usar expressões lambda

  • Uma expressão lambda pode retornar um valor e pode ter parâmetros.

  • Os parâmetros podem ser definidos de várias maneiras com uma expressão lambda.

  • Se houver uma única instrução em uma expressão lambda, não há necessidade de chaves, ao passo que, se houver várias instruções, as chaves e o valor de retorno são essenciais para serem escritos.

  • Com expressões lambda, é possível acessar variáveis ​​presentes fora do bloco de expressão lambda por um recurso conhecido como encerramento. O uso de fechamento deve ser feito com cautela para evitar qualquer problema.

  • É impossível executar qualquer código não seguro dentro de qualquer expressão lambda.

  • As expressões lambda não devem ser usadas no lado esquerdo do operador.