Expressões lambda

Escolha uma expressão lambda quando quiser passar uma operação curta para outro método e a operação estiver mais clara ao lado da chamada que a usa. Uma regra embutida mostra aos leitores como você seleciona ou transforma itens; um método nomeado permite que eles sigam a finalidade da operação antes de inspecionar seus detalhes.

Dica

Este artigo ensina opções práticas para desenvolvedores que conhecem métodos e coleções em C#. Para obter a sintaxe lambda completa e as regras, consulte a referência de expressões lambda.

Uma expressão lambda é uma função sem nome que você escreve onde outra parte do código precisa de comportamento.

A lambda a seguir aceita uma session e retorna se a session tem assentos disponíveis:

session => session.Registered < session.Capacity

O operador => separa os parâmetros à esquerda do corpo à direita. Leia como "vai para".

Passar o comportamento para um método

Muitas APIs do .NET aceitam um delegate, que é um tipo que representa um comportamento com uma lista de parâmetros específica e um tipo de retorno. Uma lambda fornece esse comportamento. Para obter uma introdução aos tipos de delegado, como Func e Action, consulte expressões lambda, delegados e eventos.

O exemplo a seguir funciona com sessões de workshop. Um WorkshopSession contém um título, duração, capacidade e número de inscrições.

int maximumMinutes = 60;

var shortSessions = sessions
    .Where(session => session.DurationMinutes <= maximumMinutes)
    .OrderBy(session => session.Title);

foreach (WorkshopSession session in shortSessions)
{
    Console.WriteLine(session.Title);
}

O primeiro lambda informa Where quais sessões manter. O segundo informa OrderBy por qual valor classificar. Os métodos recebem comportamento sem saber os detalhes de qualquer regra.

Escolher uma forma de parâmetro

Escolha a forma do parâmetro mais curta que permaneça clara:

session => session.DurationMinutes <= 60

Para um parâmetro, omita parênteses quando o compilador pode inferir o tipo. Use parênteses vazios sem parâmetros:

() => DateTime.Now

Use parênteses para dois ou mais parâmetros:

(left, right) => left + right

Normalmente, o método que recebe o lambda fornece informações suficientes para o compilador inferir tipos de parâmetro. Escreva tipos explícitos quando a inferência precisar de ajuda ou quando os tipos melhorarem a clareza:

(WorkshopSession session) => session.Title

A referência de expressões lambda abrange modificadores de parâmetro, atributos, valores padrão e outras formas especializadas.

Escolha um corpo de expressão ou comando

Use uma expressão lambda quando uma única expressão calcula o resultado:

session => session.Registered < session.Capacity

Use uma lambda de instrução quando a operação precisar de mais de uma instrução. Coloque o corpo entre chaves e inclua return quando o lambda retornar um valor:

var descriptions = sessions.Select(session =>
{
    int seatsLeft = session.Capacity - session.Registered;
    string availability = seatsLeft > 0 ? $"{seatsLeft} seats left" : "full";
    return $"{session.Title}: {availability}";
});

Console.WriteLine(string.Join(Environment.NewLine, descriptions));

Mantenha as lambdas de instrução breves. Quando o corpo precisar de várias etapas ou a mesma lógica aparecer mais de uma vez, dê ao comportamento um nome descritivo com uma função local ou um método regular.

Capturar valores do escopo ao redor

Um lambda pode usar uma variável declarada no método ao redor. Esse uso é chamado de captura. No primeiro exemplo, a seleção lambda captura maximumMinutes:

int maximumMinutes = 60;
var shortSessions = sessions.Where(
    session => session.DurationMinutes <= maximumMinutes);

A captura ajuda uma regra curta a usar o contexto local. O lambda captura a variável em si, não uma cópia de seu valor. Se a variável for alterada antes da execução do lambda, o lambda verá o valor atual.

Torne o contexto necessário fácil de identificar. Se um lambda não precisar de estado ao redor, adicione static para impedir a captura acidental e tornar essa independência visível aos leitores:

var openSessions = sessions.Where(
    static session => session.Registered < session.Capacity);

Um lambda estático pode usar seus parâmetros, valores declarados, constantes e membros estáticos. Ele não pode usar variáveis locais ou o estado da instância do código circundante.

Escolher um lambda, um grupo de métodos ou uma função local

Várias formas em C# podem fornecer comportamento a um parâmetro delegado:

  • Use uma expressão lambda para um comportamento curto que seja fácil de ler ao lado da chamada.
  • Use um grupo de métodos quando um método existente tiver a assinatura necessária e seu nome explicar o comportamento.
  • Use uma função local quando o membro que contém precisar de lógica nomeada reutilizável, recursão ou um corpo muito grande para um lambda embutido.
  • Use um método comum quando vários membros precisarem do comportamento.

Um grupo de métodos é um nome de método sem sua lista de argumentos. O compilador converte o método correspondente no tipo de delegado necessário:

var openSessions = sessions.Where(HasOpenSeats);

foreach (WorkshopSession session in openSessions)
{
    Console.WriteLine($"Open: {session.Title}");
}

static bool HasOpenSeats(WorkshopSession session) =>
    session.Registered < session.Capacity;

Where(HasOpenSeats) comunica a mesma regra que Where(session => HasOpenSeats(session)) com menos código. O nome do método informa aos leitores o que a regra testa; uma comparação embutida mostra como testa essa regra. Mantenha o wrapper lambda quando ele adicionar um argumento, combinar operações ou deixar a chamada mais clara.

Para obter uma comparação local detalhada, consulte funções locais.

Consulte também