Pergunta

Eu li rapidamente o Expressão Lambda da Microsoft documentação.

Esse tipo de exemplo me ajudou a entender melhor:

delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25

Ainda assim, não entendo por que é uma inovação tão grande.É apenas um método que morre quando a “variável do método” termina, certo?Por que devo usar isso em vez de um método real?

Foi útil?

Solução

Expressões lambda são uma sintaxe mais simples para delegados anônimos e podem ser usados ​​em qualquer lugar onde um delegado anônimo possa ser usado.Contudo, o oposto não é verdade;Expressões lambda podem ser convertidas em árvores de expressão, o que permite muita mágica como LINQ to SQL.

A seguir está um exemplo de LINQ para objetos expressão usando delegados anônimos e depois expressões lambda para mostrar como eles são mais fáceis de ver:

// anonymous delegate
var evens = Enumerable
                .Range(1, 100)
                .Where(delegate(int x) { return (x % 2) == 0; })
                .ToList();

// lambda expression
var evens = Enumerable
                .Range(1, 100)
                .Where(x => (x % 2) == 0)
                .ToList();

Expressões lambda e delegados anônimos têm uma vantagem sobre escrever uma função separada:eles implementam fechamentos o que pode permitir que você passe o estado local para a função sem adicionar parâmetros à função ou criando objetos de uso único.

Árvores de expressão são um novo recurso muito poderoso do C# 3.0 que permite que uma API observe a estrutura de uma expressão em vez de apenas obter uma referência a um método que pode ser executado.Uma API só precisa transformar um parâmetro delegado em um Expression<T> parâmetro e o compilador gerará uma árvore de expressão a partir de um lambda em vez de um delegado anônimo:

void Example(Predicate<int> aDelegate);

chamado como:

Example(x => x > 5);

torna-se:

void Example(Expression<Predicate<int>> expressionTree);

Este último receberá uma representação do árvore de sintaxe abstrata que descreve a expressão x > 5.LINQ to SQL depende desse comportamento para poder transformar expressões C# nas expressões SQL desejadas para filtragem/ordenação/etc.no lado do servidor.

Outras dicas

Funções e expressões anônimas são úteis para métodos únicos que não se beneficiam do trabalho extra necessário para criar um método completo.

Considere este exemplo:

 string person = people.Find(person => person.Contains("Joe"));

contra

 public string FindPerson(string nameContains, List<string> persons)
 {
     foreach (string person in persons)
         if (person.Contains(nameContains))
             return person;
     return null;
 }

Estes são funcionalmente equivalentes.

Eu os achei úteis em uma situação em que queria declarar um manipulador para o evento de algum controle, usando outro controle. Para fazê -lo normalmente, você teria que armazenar as referências dos controles nos campos da classe para que você pudesse usá -los em um método diferente do que eles foram criados.

private ComboBox combo;
private Label label;

public CreateControls()
{
    combo = new ComboBox();
    label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged);
}

void combo_SelectedIndexChanged(object sender, EventArgs e)
{
    label.Text = combo.SelectedValue;
}

Graças às expressões Lambda, você pode usá -lo assim:

public CreateControls()
{
    ComboBox combo = new ComboBox();
    Label label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;};
}

Muito facil.

Lambda limpa a sintaxe do delegado anônimo C# 2.0 ... por exemplo

Strings.Find(s => s == "hello");

Foi feito em C# 2.0 assim:

Strings.Find(delegate(String s) { return s == "hello"; });

Funcionalmente, eles fazem exatamente a mesma coisa, é apenas uma sintaxe muito mais concisa.

Esta é apenas uma maneira de usar uma expressão de lambda. Você pode usar uma expressão lambda qualquer lugar Você pode usar um delegado. Isso permite que você faça coisas assim:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

strings.Find(s => s == "hello");

Este código pesquisará a lista para uma entrada que corresponde à palavra "Hello". A outra maneira de fazer isso é realmente passar um delegado para o método de localização, como este:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

private static bool FindHello(String s)
{
    return s == "hello";
}

strings.Find(FindHello);

EDITAR:

No C# 2.0, isso pode ser feito usando a sintaxe do delegado anônimo:

  strings.Find(delegate(String s) { return s == "hello"; });

Lambda limpou significativamente essa sintaxe.

A Microsoft nos deu uma maneira mais limpa e mais conveniente de criar delegados anônimos chamados expressões Lambda. No entanto, não há muita atenção sendo dada ao expressões parte desta afirmação. A Microsoft lançou um espaço para nome inteiro, System.Linq.Expressões, que contém classes para criar árvores de expressão com base nas expressões lambda. As árvores de expressão são compostas de objetos que representam a lógica. Por exemplo, x = y + z é uma expressão que pode fazer parte de uma árvore de expressão no .NET. Considere o seguinte exemplo (simples):

using System;
using System.Linq;
using System.Linq.Expressions;


namespace ExpressionTreeThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object
            var del = expr.Compile(); //compiles the object to a CLR delegate, at runtime
            Console.WriteLine(del(5)); //we are just invoking a delegate at this point
            Console.ReadKey();
        }
    }
}

Este exemplo é trivial. E tenho certeza de que você está pensando: "Isso é inútil, pois eu poderia ter criado diretamente o delegado em vez de criar uma expressão e compilá -lo em tempo de execução". E você estaria certo. Mas isso fornece a base para as árvores de expressão. Existem várias expressões disponíveis nos namespaces de expressões e você pode construir o seu próprio. Eu acho que você pode ver que isso pode ser útil quando você não sabe exatamente o que o algoritmo deve estar no tempo de design ou compilação. Vi um exemplo em algum lugar para usar isso para escrever uma calculadora científica. Você também pode usá -lo para Bayesiano sistemas, ou para Programação genética (Ai). Algumas vezes na minha carreira, tive que escrever funcionalidade semelhante ao Excel, que permitia aos usuários inserir expressões simples (adição, subtrações etc.) para operar nos dados disponíveis. No pré-. Agora eu usaria árvores de expressão.

Isso evita que métodos que são usados ​​apenas uma vez em um local específico sejam definidos longe do local em que são usados.Bons usos são como comparadores para algoritmos genéricos, como classificação, onde você pode definir uma função de classificação personalizada onde você está invocando a classificação, em vez de forçá-lo a procurar outro lugar para ver o que está classificando.

E não é realmente uma inovação.LISP possui funções lambda há cerca de 30 anos ou mais.

Uma expressão lambda é como um método anônimo escrito no lugar de uma instância delegada.

delegate int MyDelagate (int i);
MyDelagate delSquareFunction = x => x * x;

Considere a expressão lambda x => x * x;

O valor do parâmetro de entrada é x (no lado esquerdo de =>)

A lógica da função é x * x (no lado direito de =>)

O código de uma expressão lambda pode ser um bloco de instruções em vez de uma expressão.

x => {return x * x;};

Exemplo

Observação: Func é um delegado genérico predefinido.

    Console.WriteLine(MyMethod(x => "Hi " + x));

    public static string MyMethod(Func<string, string> strategy)
    {
        return strategy("Lijo").ToString();
    }

Referências

  1. Como um delegado e uma interface podem ser usados ​​de forma intercambiável?

Você também pode encontrar o uso de expressões Lambda na redação de códigos genéricos para agir em seus métodos.

Por exemplo: Função genérica para calcular o tempo gasto por uma chamada de método. (ou seja Action aqui)

public static long Measure(Action action)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    action();
    sw.Stop();
    return sw.ElapsedMilliseconds;
}

E você pode chamar o método acima usando a expressão Lambda da seguinte maneira,

var timeTaken = Measure(() => yourMethod(param));

A expressão permite que você obtenha o valor de retorno do seu método e fora do param

var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));

Muitas vezes, você está usando apenas a funcionalidade em um só lugar, portanto, fazer um método apenas agarra a classe.

A expressão lambda é uma maneira concisa de representar um método anônimo. Os métodos anônimos e as expressões Lambda permitem definir a implementação do método em linha, no entanto, um método anônimo exige explicitamente que você defina os tipos de parâmetros e o tipo de retorno para um método. A expressão lambda usa o recurso de inferência de tipo do C# 3.0, que permite ao compilador inferir o tipo de variável com base no contexto. É muito conveniente porque isso nos salva muito digitar!

É uma maneira de fazer uma pequena operação e colocá -la muito perto de onde é usado (não muito diferente de declarar uma variável próxima ao seu ponto de uso). Isso deve tornar seu código mais legível. Ao anonimizar a expressão, você também está tornando muito mais difícil para alguém quebrar o código do seu cliente, se a função for usada em outro lugar e modificada para "aprimorá -lo".

Da mesma forma, por que você precisa usar o foreach? Você pode fazer tudo em forach com uma planície para o loop ou apenas usar diretamente o iEnumerable. Resposta: Você não precisar Mas torna seu código mais legível.

A inovação está no tipo segurança e transparência.Embora você não declare tipos de expressões lambda, elas são inferidas e podem ser usadas por pesquisa de código, análise estática, ferramentas de refatoração e reflexão em tempo de execução.

Por exemplo, antes você poderia ter usado SQL e sofrer um ataque de injeção de SQL, porque um hacker passou uma string onde normalmente era esperado um número.Agora você usaria uma expressão lambda LINQ, que está protegida disso.

Não é possível criar uma API LINQ em delegados puros, pois é necessário combinar árvores de expressão antes de avaliá-las.

Em 2016, a maioria dos idiomas populares têm expressão lambda suporte, e C# foi um dos pioneiros nesta evolução entre as principais linguagens imperativas.

Esta é talvez as melhores explicações sobre o porquê de usar expressões Lambda -> https://youtu.be/j9nj5dto54q

Em resumo, é para melhorar a legibilidade do código, reduzir as chances de erros reutilizando, em vez de replicar o código e alavancar a otimização do que está acontecendo nos bastidores.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top