Expressões lambda (guia de programação do C#)

Uma expressão lambda é uma função anônimo que você pode usar para criar representantes ou tipos de árvore de expressão.Usando expressões lambda, você pode gravar as funções local que podem ser passados como argumentos ou ser retornadas como o valor de chamadas de função.Expressões Lambda são particularmente úteis para escrever expressões de consulta LINQ.

Para criar uma expressão lambda, você especifica parâmetros de entrada (se houver) no lado esquerdo do operador =>lambda, e você coloca o bloco de expressão ou instrução do outro lado.Por exemplo, a expressão lambda x => x * x especifica um parâmetro que é chamado x e retorna o valor de x esquadrou.Você pode atribuir essa expressão para um tipo de representante, como mostra o exemplo a seguir:

delegate int del(int i);
static void Main(string[] args)
{
    del myDelegate = x => x * x;
    int j = myDelegate(5); //j = 25
}

Para criar um tipo de árvore de expressão:

using System.Linq.Expressions;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<del> myET = x => x * x;
        }
    }
}

O operador de => tem a mesma precedência que a atribuição (=) e é mostrado associativo.

Lambdas é usado em consultas método base de LINQ como argumentos para métodos padrão de operador de consulta como Where.

Quando você usa a sintaxe método base para chamar o método de Where na classe de Enumerable (como fazer em LINQ aos objetos e para LINQ to XML) o parâmetro é um tipo System.Func<T, TResult>delegado.Uma expressão lambda é a maneira mais conveniente de criar esse representante.Quando você chama o método no mesmo, por exemplo, a classe de System.Linq.Queryable (como fazer em LINQ to SQL) no tipo de parâmetro é System.Linq.Expressions.Expression<Func> funcional é onde todos os representantes e com até a dezesseis parâmetros de entrada.Além de isso, uma expressão lambda é apenas uma maneira muito concisa de construir a árvore de expressão.Os lambdas permitem que chamadas de Where pareçam semelhantes embora na verdade o tipo de objeto criado lambda seja diferente.

Em o exemplo anterior, observe que a assinatura do representante tem um parâmetro de entrada implícito- tipado de tipo int, e retornar int.A expressão lambda pode ser convertida para um representante de esse tipo porque também tem um parâmetro de entrada (x) e um valor de retorno que o compilador pode converter implicitamente para o tipo int.(Inferência de tipos é discutida em detalhes nas seções seguintes.) Quando o representante é chamado usando um parâmetro de entrada de 5, retornará um resultado de 25.

Lambdas não é permitido no lado esquerdo do operador de é ou de como .

Todas as restrições que se aplicam aos métodos anônimos também se aplicam às expressões lambda.Para obter mais informações, consulte Métodos anônimos (guia de programação do C#).

expressão Lambdas

Uma expressão lambda com uma expressão no lado direito é chamada uma expressão lambda.Os lambdas de expressão são usados amplamente na compilação de Árvores de expressão (C# e Visual Basic).Uma expressão lambda retorna o resultado da expressão e tem a seguinte forma: básico

(input parameters) => expression

Os parênteses são opcionais somente se o método tem um parâmetro de entrada; se não são necessários.Dois ou mais parâmetros de entrada são separados por vírgulas colocado entre parênteses:

(x, y) => x == y

A as vezes é difícil ou impossível para o compilador inferir os tipos de entrada.Quando isso ocorre, você pode especificar explicitamente os tipos conforme mostrado no exemplo o seguir:

(int x, string s) => s.Length > x

Especifique os parâmetros de entrada zero com parênteses vazios:

() => SomeMethod()

Observe no exemplo anterior que o corpo de uma expressão lambda pode consistir de uma chamada de método.Em o entanto, se você estiver criando árvores de expressão que serão consumidas em outro domínio, como SQL Server, você não deve usar chamadas de método em expressões lambda.Os métodos não tenham significado fora do contexto do common language runtime .NET.

instrução Lambdas

Uma instrução lambda lembra a uma expressão lambda exceto que a declaração está inclusa fixa:

(input parameters) => {statement;}

O corpo de uma instrução lambda pode consistir de qualquer número de declarações; no entanto, isso não há geralmente não mais de dois ou três.

delegate void TestDelegate(string s);
…
TestDelegate myDel = n => { string s = n + " " + "World"; Console.WriteLine(s); };
myDel("Hello");

Os lambdas a declaração, como métodos anônimos, não podem ser usados para criar árvores de expressão.

Async Lambdas

Você pode facilmente criar as instruções e expressões lambda que incorporam o processamento assíncrona usando as palavras-chave de async e de await .Por exemplo, o seguinte exemplo de formulários do windows contém um manipulador de eventos que chama e espere um método de async, ExampleMethodAsync.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private async void button1_Click(object sender, EventArgs e)
    {
        // ExampleMethodAsync returns a Task.
        await ExampleMethodAsync();
        textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

você pode adicionar o mesmo manipulador de eventos usando um async lambda.Para adicionar esse manipulador, adicione um modificador de async antes da lista de parâmetros lambda, como mostra o exemplo a seguir.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        button1.Click += async (sender, e) =>
        {
            // ExampleMethodAsync returns a Task.
            await ExampleMethodAsync();
            textBox1.Text += "\r\nControl returned to Click event handler.\r\n";
        };
    }

    async Task ExampleMethodAsync()
    {
        // The following line simulates a task-returning asynchronous process.
        await Task.Delay(1000);
    }
}

Para obter mais informações sobre como criar e usar métodos de async, consulte Programação com Async assíncrona e esperar (C# e Visual Basic).

Lambdas com os operadores de consulta padrão

Muitos operadores de consulta padrão têm um parâmetro de entrada cujo tipo é de uma família de Func<T, TResult> de representantes genéricos.Delegados de Func<T, TResult> usam parâmetros de tipo para definir o número e o tipo de parâmetros de entrada, e o tipo de retorno do delegado.delegados deFunc é muito útil para encapsular as expressões definidos pelo usuário que são aplicadas a cada elemento em um conjunto de dados de origem.Por exemplo, considere o seguinte tipo delegado:

public delegate TResult Func<TArg0, TResult>(TArg0 arg0)

O delegado pode ser instanciado como Func<int,bool> myFunc onde int é um parâmetro de entrada e bool é o valor de retorno.O valor de retorno é sempre especificado no parâmetro do tipo mais recente.Func<int, string, bool> define um delegado com dois parâmetros de entrada, int e string, e um tipo de retorno de bool.O exemplo a seguir representante de Func , quando é chamado, retornará verdadeiro ou falso para indicar se o parâmetro de entrada é igual a 5:

Func<int, bool> myFunc = x => x == 5;
bool result = myFunc(4); // returns false of course

Você também pode fornecer uma expressão lambda quando o tipo de argumento é Expression<Func>, por exemplo nos operadores de consulta padrão que são definidos em System.Linq.Queryable.Quando você especifica um argumento de Expression<Func> , o método será compilado em uma árvore de expressão.

Um operador de consulta padrão, o método de Count , é mostrado aqui:

int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
int oddNumbers = numbers.Count(n => n % 2 == 1);

O compilador pode inferir o tipo de parâmetro de entrada, ou você pode também especifica explicitamente.Esta expressão lambda detalhes de conta esses números inteiros (n) que quando dividida por dois tem resto 1.

O seguinte método irá gerar uma seqüência que contém todos os elementos na matriz de numbers que são para o lado esquerdo de 9 porque é o primeiro número na seqüência que não está de acordo com a condição:

var firstNumbersLessThan6 = numbers.TakeWhile(n => n < 6);

este exemplo mostra como especificar vários parâmetros de entrada incluindo os entre parênteses.O método retorna todos os elementos na matriz de números até que um número seja localizado cujo valor é menor que sua posição.Não confunda o operador lambda (=>) com o maior que ou não iguale o operador>=().

var firstSmallNumbers = numbers.TakeWhile((n, index) => n >= index);

inferência de tipos em Lambdas

A o escrever lambdas, você geralmente não precisa especificar um tipo para os parâmetros de entrada porque o compilador pode inferir o tipo com base no corpo lambda, o tipo delegate subjacente, e outros fatores como descrito na especificação da linguagem C#.Para a maioria dos operadores de consulta padrão, a primeira entrada é o tipo dos elementos na seqüência de origem.Se você estiver verificando IEnumerable<Customer>, então a variável de entrada é inferido para ser um objeto de Customer , o que significa que tenham acesso a seus métodos e propriedades:

customers.Where(c => c.City == "London");

As regras gerais para lambdas são:

  • O método deve conter o mesmo número de parâmetros como o tipo delegado.

  • Cada parâmetro de entrada no método deve ser implicitamente conversível para o parâmetro correspondente do delegado.

  • O valor de retorno lambda (se houver) deve ser implicitamente conversível para o tipo de retorno do delegado.

Observe que as expressões lambda em se não têm um tipo porque o CTS não tem nenhum conceito de “intrínseco da expressão lambda.” Em o entanto, às vezes é conveniente falar informal de “tipo” de uma expressão lambda.Em esses casos o tipo refere-se ao tipo de representante ou o tipo de Expression que a expressão lambda é convertida.

Escopo variável em expressões Lambda

Lambdas pode referir-se a variável externos que estão no escopo no método incluindo ou digite que o método está definido.Variáveis que são capturados assim são armazenados para uso na expressão lambda mesmo se as variáveis sairiam de outra maneira de escopo e poderiam ser coletado como lixo.Uma variável externa deve ser definida atribuído antes que possa ser consumido em uma expressão lambda.O exemplo demonstra estas regras:

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:
        // Output: j = 0 
        // The delegate has not been invoked yet.
        Console.WriteLine("j = {0}", j);        // Invoke the delegate.
        bool boolResult = del();

        // Output: j = 10 b = True
        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);

        // Output: True
        Console.WriteLine(result);
           
        Console.ReadKey();
    }
}

As seguintes regras se aplicam ao escopo variável em expressões lambda:

  • Uma variável que é capturado lixo- não será coletado até o representante que referências que sai do escopo.

  • Variáveis introduzidos em uma expressão lambda não são visíveis no método externo.

  • Uma expressão lambda não pode diretamente capturar um parâmetro de ref ou de out de um método delimitador.

  • Uma instrução return em uma expressão lambda não causa incluindo o método para retornar.

  • Uma expressão lambda não pode conter uma instrução de goto , a instrução de break , ou a declaração de continue cujo destino está fora do corpo ou no corpo de uma função anônimo contida.

Especificação da linguagem C#

Para obter mais informações, consulte Especificação de linguagem do C# A especificação da linguagem é a fonte definitiva para a sintaxe e o uso da linguagem C#.

Capítulo caracterizado book

Delegates, Events, and Lambda Expressions Em C# 3.0 Cookbook, Third Edition: More than 250 solutions for C# 3.0 programmers

Consulte também

Referência

Métodos anônimos (guia de programação do C#)

é (referência de C#)

Conceitos

Guia de programação do C#

Árvores de expressão (C# e Visual Basic)

Outros recursos

LINQ (consulta integrada à linguagem)

Expressões lambda recursivos