Expressões Lambda C#

Resumo : neste tutorial, você aprenderá sobre expressões lambda C# e como usá-las para definir funções anônimas.

Introdução às expressões lambda C#

Uma expressão lambda é um método anônimo escrito no lugar de uma instância delegada . Uma expressão lambda é usada para criar uma função anônima.

Uma expressão lambda pode ter uma de duas formas: expressão lambda e instrução lambda.

Uma expressão lambda possui uma expressão em seu corpo:

(parameters) => expressionLinguagem de código:  C#  ( cs )

Uma instrução lambda tem um bloco de instruções como corpo:

(parameters) => { statements; }Linguagem de código:  C#  ( cs )

Nesta sintaxe, o =>é chamado de operador lambda.

Para formar uma expressão lambda, você especifica parâmetros de entrada no lado esquerdo do operador lambda e uma expressão ou bloco de instrução no lado direito.

Se uma expressão lambda não tiver nenhum parâmetro de entrada, você poderá usar parênteses vazios (). Por exemplo:

() => expression;Linguagem de código:  C#  ( cs )

Se uma expressão lambda tiver exatamente um parâmetro e o compilador C# puder inferir o tipo do parâmetro, você poderá omitir os parênteses desta forma:

Func<T, TResult> lambda = parameter => expression;Linguagem de código:  C#  ( cs )

Se uma expressão lambda tiver vários parâmetros, você poderá usar uma vírgula para separar dois parâmetros da seguinte maneira:

(p1, p2, p3) => expression;Linguagem de código:  C#  ( cs )

Exemplos de expressões lambda em C#

O exemplo a seguir define uma expressão lambda que retorna o quadrado de um número inteiro:

var square = (int x) => x * x;
var result = square(10);

Console.WriteLine(result); // 100Linguagem de código:  C#  ( cs )

Neste exemplo, o seguinte é uma expressão lambda:

(int x) => x * x;Linguagem de código:  C#  ( cs )

Ele aceita um número inteiro e retorna o quadrado desse número inteiro.

Se quiser usar a instrução lambda, você precisará usar uma instrução return dentro do bloco de instruções. Por exemplo:

var square = (int x) =>
{
    return x * x;
};

var result = square(10);
Console.WriteLine(result); // 100Linguagem de código:  C#  ( cs )

Observe que você pode especificar explicitamente o tipo de retorno de uma expressão lambda. Por exemplo, o seguinte usa explicitamente int como o tipo de retorno da expressão lambda:

var square = int (int x) => x * x;
var result = square(10);

Console.WriteLine(result); // 100Linguagem de código:  C#  ( cs )

Quando o compilador C# encontra uma expressão lambda, ele converte a expressão lambda em uma instância delegada. No exemplo acima, o compilador C# converte a expressão lambda em Func<int,int>. Veja o exemplo a seguir:

Func<int,int> square = x => x * x;
var result = square(10);

Console.WriteLine(result); // 100Linguagem de código:  C#  ( cs )

Neste exemplo, declaramos the squarecomo uma instância do Func<int,int>.

Como Func<int, int>aceita um número inteiro e retorna um número inteiro, não precisamos especificar explicitamente o tipo do parâmetro de entrada da expressão lambda. Portanto, podemos omitir os parênteses.

Capturando variáveis ​​externas

Uma expressão lambda pode fazer referência a quaisquer variáveis, incluindo variáveis ​​locais, parâmetros e membros acessíveis no local onde você define a expressão lambda. Essas variáveis ​​são chamadas de variáveis ​​externas .

As variáveis ​​referenciadas por uma expressão lambda são conhecidas como variáveis ​​capturadas . Quando uma expressão lambda captura variáveis, ela é chamada de encerramento . Por exemplo:

int factor = 10;

var multiplier = (int x) => x * factor;

var result = multiplier(10);

Console.WriteLine(result); // 100Linguagem de código:  C#  ( cs )

Neste exemplo, a expressão lambda faz referência à variável local factor. A factorvariável é chamada de variável externa. E a expressão lambda é um encerramento.

É importante observar que a expressão lambda avalia as variáveis ​​capturadas quando é executada, e não quando as variáveis ​​foram capturadas. Por exemplo:

var multipliers = new List<Func<int, int>>();

for(int i = 1; i <= 3; i++)
{
    multipliers.Add((int x) => x*i);
}



foreach (var multipler in multipliers)
{
    int result = multipler(10);
    Console.WriteLine(result);
}Linguagem de código:  C#  ( cs )

Como funciona.

Primeiro, defina uma lista de expressões lambda que aceitam um número inteiro e retornam um número inteiro:

var multipliers = new List<Func<int, int>>();Linguagem de código:  C#  ( cs )

Segundo, adicione três multiplicadores à lista. Cada multiplicador multiplicará seu argumento por 1, 2 e 3.

for(int i = 1; i <= 3; i++)
{
    multipliers.Add((int x) => x*i);
}Linguagem de código:  C#  ( cs )

Terceiro, itere sobre a lista de expressões lambda e execute cada uma delas:

foreach (var multipler in multipliers)
{
    int result = multipler(10); // multipler uses 4
    Console.WriteLine(result);
}Linguagem de código:  C#  ( cs )

A saída não é o que você espera:

40
40
40Linguagem de código:  C#  ( cs )

Retorna o mesmo resultado (40) para as três expressões lambda.

A razão é que após o primeiro loop for, a variável ié 4. Porque as expressões lambda avaliam as variáveis ​​de captura no momento da invocação, não no momento definido. Portanto, todas as três expressões lambda usam o mesmo valor da variável i.

Para corrigir isso, você precisa criar uma variável local dentro do forloop e usar essa variável como a variável capturada para as expressões lambda, assim:

var multipliers = new List<Func<int, int>>();

for(int i = 1; i <= 3; i++)
{
    int factor = i;
    multipliers.Add((int x) => x*factor);
}

foreach (var multipler in multipliers)
{
    int result = multipler(10); 
    Console.WriteLine(result);
}Linguagem de código:  C#  ( cs )

Saída:

10
20
30Linguagem de código:  C#  ( cs )

Neste exemplo, cada iteração cria uma nova factorvariável. Portanto, cada expressão lambda captura uma variável diferente.

Expressões lambda estáticas

Quando uma expressão lambda captura variáveis, o compilador C# precisa criar uma classe privada e instanciá-la para armazenar uma referência às variáveis ​​capturadas. Isso acarreta um pequeno desempenho.

A partir do C# 9, você pode usar uma palavra-chave estática para garantir que a expressão lambda não capture nenhuma variável. Por exemplo:

var square = static (int x) => x * x;
var result = square(10);

Console.WriteLine(result); // 100Linguagem de código:  C#  ( cs )

Ao usar a staticpalavra-chave e capturar variáveis, o compilador C# emitirá um erro. Por exemplo:

int factor = 2;
var square = static (int x) => x * factor; // ERROR

var result = square(10);
Console.WriteLine(result); // 100Linguagem de código:  C#  ( cs )

Resumo

  • Uma expressão lambda define uma função anônima.
  • Uma expressão lambda pode capturar variáveis.
  • Quando uma expressão lambda contém variáveis ​​capturadas, ela é chamada de encerramento.
  • Uma expressão lambda avalia as variáveis ​​capturadas no momento da invocação.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *