Compreender as expressões Lambda e os delegados [fechado]

Eu tenho tentado descobrir isso por algum tempo (lendo blogs online e articlaes), mas até agora sem sucesso.

O que são delegados? O que são expressões Lambda? Vantagens e desvantagens de ambos? As melhores práticas possíveis de quando usar uma ou outra?

Obrigado antecipadamente.

Author: user279521, 2010-07-19

6 answers

Os delegados são métodos que você pode usar como variáveis, como strings, etc. Por exemplo, você pode declarar um método de delegado com um argumento:

delegate void OneArgumentDelegate(string argument);
Não faz nada, como uma interface. Se você tem um método em qualquer classe com um argumento como este:
void SomeMethod(string someArgument) {}

IT matches the signature of the delegate, and thus can be assigned to a variable of its type:

OneArgumentDelegate ThisIsAVariable = new OneArgumentDelegate(SomeMethod);
OneArgumentDelegate ThisIsAlsoAVariable = SomeMethod; // Shorthand works too

Estes podem então ser passados como argumentos a métodos e invocados, como então ...

void Main()
{
  DoStuff(PrintString);
}

void PrintString(string text)
{
  Console.WriteLine(text);
}

void DoStuff(OneArgumentDelegate action) 
{
  action("Hello!");
}

Isto irá produzir Hello!.

As expressões Lambda são uma abreviatura para a {[[6]} assim você não tem que criar um método para cada variável delegada que você vai usar. Você 'cria' um método temporário que é passado para o método. Funciona assim:

DoStuff(string text => Console.WriteLine(text)); // single line
DoStuff(string text => // multi line
{
  Console.WriteLine(text);
  Console.WriteLine(text);
});
As expressões Lambda são apenas uma abreviatura, mais vale criar um método separado e transmiti-lo. Espero que entendas melhor agora; -)
 26
Author: Jouke van der Maas, 2010-07-19 14:57:16

O delegado é um objeto que possui uma referência a uma função. Vários delegados diferentes podem apontar para a mesma função. Adelegate 's type defines the footprint of a function it may point to.

A expressão Lambda é uma função que não tem nome. A única maneira de executar esta função é ter um delegado apontando para a função. As expressões Lambda são normalmente definidas no local onde é necessário um delegado para uma função com uma dada pegada. Isto é útil para tornar o código menos descritivo e ao mesmo tempo mais descritivo e flexível

Sugiro que use uma função com nome e um delegado para ela sempre que tenha algum código que vai ser chamado de diferentes lugares. Um exemplo comum é um ouvinte de eventos que você quer Anexar a vários produtores de eventos.

Outro ponto a considerar escrever uma função separada é a complexidade do Código. Não vai ajudar ninguém se escreveres um todo o programa dentro de uma expressão lambda.

Por outro lado, você muitas vezes precisa de algum processamento trivial que você quer ser executado de uma forma de callback. Este é o ponto onde você pode amar as expressões lambda.

O que é muito bom sobre as expressões lambda que eles herdam o escopo em que foram definidos, de modo que você pode facilmente suas variáveis dentro da expressão lambda, e, assim, passar um monte de informações dentro. Você deve ter cuidado no entanto, veja a seção Observações de Este artigo.

Os Labdas são brilhantes em conjunto com o LINQ.

Para concluir, tenho de citar mais uma secção must-read msdn:

Quando você usa a sintaxe baseada em métodos para chamar o método de onde na classe enumerável (como você faz em LINQ para objetos e LINQ para XML) o parâmetro é um sistema de tipo delegado.Funcao. Uma expressão lambda é a maneira mais conveniente para criar esse delegado. Quando você chama o mesmo método em, por exemplo, o Sistema.Linq.Classe Queryable (como você faz em LINQ para SQL) então o tipo de parâmetro é um sistema.Linq.Expressao.Expressão onde o Func é qualquer delegado do Func com até dezesseis parâmetros de entrada. Mais uma vez, uma expressão lambda é apenas uma forma muito concisa de construir essa árvore de expressão. Os lambdas permitem que as chamadas de onde pareçam semelhantes, embora de fato o tipo de objeto criado a partir do lambda seja diferente.
 6
Author: ULysses, 2010-07-19 15:25:34
Ninguém mencionou delegados anónimos. Você pode criar delegados em tempo real, sem declará-los:
public void Action(Func<int, int> func);
...
Action(delegate(int x) { return x*x; });

Que é apenas uma versão mais descritiva da sintaxe lambda:

Action(x => x*x);

Note também que a sintaxe lambda tem inferência tipo mais agressiva. Outra diferença é que a notação lambda pode ser usada para declarar árvores de expressão:

public void Action(Expression<Func<int, int>>);
Action(x => x*x);

Nesse caso, o que se obtém não é uma função, mas uma árvore de análise que se pode examinar em tempo de execução. Presente é como linq queries construir seu sql, por exemplo.

Editar

Para responder mais directamente à questão de quando usar uma ou outra:

Raramente é necessário declarar um novo tipo de delegado, embora ocasionalmente seja útil. O framework fornece vários tipos Func<>, juntamente com Action<T> e Predicate<T> que são geralmente tudo o que você precisa.

Ao criar uma função 'on THE fly', não há vantagem em usar a sintaxe de delegado anónimo em vez da sintaxe lambda. Uma vez que a sintaxe lambda é mais concisa e tipo-inferido, preferi-lo.

 3
Author: Gabe Moothart, 2010-07-19 15:47:37

O delegado é apenas um indicador para a função. É como uma "variável", onde você pode salvar o endereço para outra função que será chamada

    public class test {
    Action<int> CallUserCode;

    public test(Action<int> proc){
        CallUserCode = proc;
    }

    void foo(){
        int someValue = 0;
        //do some stuff that needs to call the user procedure
        CallUserCode(someValue);
    }
}

Lambda Expressions is too a delegate, which has simplified syntax and can "create" functions "inline". Assim, o exemplo anterior seria chamado usando lambda da seguinte forma.

void bar(){
    var t = new test(x => { /* do something with the value i get from foo */});
    t.foo();  //here function foo gets called, which will call 'do something' AND call my lambda expression
}
 2
Author: Markos, 2010-07-19 14:58:23
Há uma diferença importante em que podemos usar o lamda do que o delegado.
private delegate int emptymethoddel();
// Delegate for method with no params and returns int

O tipo de delegado-quadro equivalente é:: Func<int>

Mas não pode criar uma nova instância/func de delegado a partir do método parametrizado.

private int TwoArgMethod(int i, int j)
{
    return i + j;
}

Mas, com lambda, você pode obter delegado para o método acima.

Func<int> retmethod = () => TwoArgMethod(10, 20);
Mas para a instanciação do delegado, não podemos fazer o que está abaixo.
emptymethoddel retmethod4 = new emptymethoddel(TwoArgMethod(10,20)); 
// mismatch method signature
Com o lambda, podemos dar indicações a métodos que não coincidam com o "Func" ou qualquer outro. variante.
 2
Author: Srav, 2012-04-03 19:03:43
Como os outros disseram, lambdas são uma sintaxe para criar delegados inline e anonimamente. Uma coisa que você pode fazer com lambdas que não é possível com funções tradicionais são fechamentos. Desta forma, poderá criar funções em tempo de execução com a informação de tempo de execução:
string mystring = SomeObject.GetMyString();
AnotherObject.OnSomeEvent += (eventparams => 
{
  string newstring = string.Format(eventparams.Message, mystring);
  SomeService.PrintEvent(newstring);
}

Desta forma, mystring é incorporado no delegado e pode ser usado como uma variável.

 1
Author: Ozan, 2010-07-19 15:23:05