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) => expression
Linguagem 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); // 100
Linguagem 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); // 100
Linguagem 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); // 100
Linguagem 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); // 100
Linguagem de código: C# ( cs )
Neste exemplo, declaramos the square
como 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); // 100
Linguagem de código: C# ( cs )
Neste exemplo, a expressão lambda faz referência à variável local factor
. A factor
variá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
40
Linguagem 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 for
loop 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
30
Linguagem de código: C# ( cs )
Neste exemplo, cada iteração cria uma nova factor
variá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); // 100
Linguagem de código: C# ( cs )
Ao usar a static
palavra-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); // 100
Linguagem 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.