Pergunta

Essa pergunta me faz muito e pensei em solicitar algumas sugestões sobre como descrever melhor a diferença.

Foi útil?

Solução

Na verdade, são duas coisas muito diferentes."Delegado" é na verdade o nome de uma variável que contém uma referência a um método ou lambda, e um lambda é um método sem um nome permanente.

Lambdas são muito parecidos com outros métodos, exceto por algumas diferenças sutis.

  1. Um método normal é definido em um "declaração" e vinculado a um nome permanente, enquanto um lambda é definido "on the fly" em um "expressão" e não tem nome permanente.
  2. Alguns lambdas podem ser usados ​​com árvores de expressão .NET, enquanto os métodos não.

Um delegado é definido assim:

delegate Int32 BinaryIntOp(Int32 x, Int32 y);

Uma variável do tipo BinaryIntOp pode ter um método ou um labmda atribuído a ela, desde que a assinatura seja a mesma:dois argumentos Int32 e um retorno Int32.

Um lambda pode ser definido assim:

BinaryIntOp sumOfSquares = (a, b) => a*a + b*b;

Outra coisa a notar é que embora os tipos Func e Action genéricos sejam frequentemente considerados "tipos lambda", eles são como quaisquer outros delegados.O bom deles é que eles essencialmente definem um nome para qualquer tipo de delegado que você possa precisar (até 4 parâmetros, embora você certamente possa adicionar mais).Portanto, se você estiver usando uma ampla variedade de tipos de delegados, mas nenhum mais de uma vez, poderá evitar sobrecarregar seu código com declarações de delegados usando Func e Action.

Aqui está uma ilustração de como Func e Action "não são apenas para lambdas":

Int32 DiffOfSquares(Int32 x, Int32 y)
{
  return x*x - y*y;
}

Func<Int32, Int32, Int32> funcPtr = DiffOfSquares;

Outra coisa útil a saber é que os tipos delegados (não os próprios métodos) com a mesma assinatura, mas com nomes diferentes, não serão convertidos implicitamente entre si.Isto inclui os delegados Func e Action.No entanto, se a assinatura for idêntica, você poderá converter explicitamente entre elas.

Indo além....Em C# as funções são flexíveis, com o uso de lambdas e delegados.Mas C# não possui "funções de primeira classe".Você pode usar o nome de uma função atribuído a uma variável delegada para essencialmente criar um objeto que representa essa função.Mas é realmente um truque do compilador.Se você iniciar uma instrução escrevendo o nome da função seguido de um ponto (ou seja,tente fazer acesso de membro na própria função) você descobrirá que não há membros para referência.Nem mesmo os do Object.Isso evita que o programador faça coisas úteis (e potencialmente perigosas, é claro), como adicionar métodos de extensão que podem ser chamados em qualquer função.O melhor que você pode fazer é estender a própria classe Delegate, o que certamente também é útil, mas não tanto.

Atualizar:Veja também A resposta de Karg ilustrando a diferença entre delegados anônimos vs.métodos e lambdas.

Atualização 2: James Hart faz uma observação importante, embora muito técnica, de que lambdas e delegados não são entidades .NET (ou seja,o CLR não tem conceito de delegado ou lambda), mas são estruturas e construções de linguagem.

Outras dicas

A pergunta é um pouco ambígua, o que explica a grande disparidade nas respostas que você está obtendo.

Na verdade, você perguntou qual é a diferença entre lambdas e delegados no framework .NET;isso pode ser uma entre várias coisas.Você está perguntando:

  • Qual é a diferença entre expressões lambda e delegados anônimos na linguagem C# (ou VB.NET)?

  • Qual é a diferença entre objetos System.Linq.Expressions.LambdaExpression e objetos System.Delegate no .NET 3.5?

  • Ou algo em algum lugar entre ou próximo a esses extremos?

Algumas pessoas parecem estar tentando responder à pergunta 'qual é a diferença entre expressões C# Lambda e .NET System.Delegate?', o que não faz muito sentido.

A estrutura .NET por si só não entende os conceitos de delegados anônimos, expressões lambda ou fechamentos - tudo isso é definido pelas especificações da linguagem.Pense em como o compilador C# traduz a definição de um método anônimo em um método em uma classe gerada com variáveis ​​de membro para manter o estado de fechamento;para o .NET, não há nada anônimo no delegado;é anônimo para o programador C# que o escreve.Isso é igualmente verdadeiro para uma expressão lambda atribuída a um tipo delegado.

O que é .NET FAZ entender é a ideia de um delegado - um tipo que descreve uma assinatura de método, cujas instâncias representam chamadas vinculadas a métodos específicos em objetos específicos ou chamadas não vinculadas a um método específico em um tipo específico que pode ser invocado contra qualquer objeto daquele tipo, onde o referido método adere à referida assinatura.Todos esses tipos herdam de System.Delegate.

O .NET 3.5 também introduz o namespace System.Linq.Expressions, que contém classes para descrever expressões de código - e que também pode, portanto, representar chamadas vinculadas ou não vinculadas a métodos em tipos ou objetos específicos.As instâncias LambdaExpression podem então ser compiladas em delegados reais (por meio dos quais um método dinâmico baseado na estrutura da expressão é gerado em código e um ponteiro delegado para ele é retornado).

Em C# você pode produzir instâncias dos tipos System.Expressions.Expression atribuindo uma expressão lambda a uma variável desse tipo, o que produzirá o código apropriado para construir a expressão em tempo de execução.

Claro, se você eram perguntando qual é a diferença entre expressões lambda e métodos anônimos em C#, afinal, tudo isso é bastante irrelevante e, nesse caso, a principal diferença é a brevidade, que se inclina para delegados anônimos quando você não se importa com parâmetros e não Não planejo retornar um valor e usar lambdas quando desejar digitar parâmetros inferenciados e tipos de retorno.

E as expressões lambda suportam a geração de expressões.

Uma diferença é que um delegado anônimo pode omitir parâmetros enquanto um lambda deve corresponder à assinatura exata.Dado:

public delegate string TestDelegate(int i);

public void Test(TestDelegate d)
{}

você pode chamá-lo das quatro maneiras a seguir (observe que a segunda linha possui um delegado anônimo que não possui nenhum parâmetro):

Test(delegate(int i) { return String.Empty; });
Test(delegate { return String.Empty; });
Test(i => String.Empty);
Test(D);

private string D(int i)
{
    return String.Empty;
}

Você não pode transmitir uma expressão lambda que não tenha parâmetros ou um método que não tenha parâmetros.Não são permitidos:

Test(() => String.Empty); //Not allowed, lambda must match signature
Test(D2); //Not allowed, method must match signature

private string D2()
{
    return String.Empty;
}

Delegados são equivalentes a ponteiros de função/ponteiros de método/retornos de chamada (faça a sua escolha) e lambdas são funções anônimas bastante simplificadas.Pelo menos é o que digo às pessoas.

Não tenho muita experiência com isso, mas a forma como descreveria é que um delegado é um wrapper em torno de qualquer função, enquanto uma expressão lambda é em si uma função anônima.

Um delegado é sempre basicamente um ponteiro de função.Um lambda pode se transformar em um delegado, mas também pode se transformar em uma árvore de expressões LINQ.Por exemplo,

Func<int, int> f = x => x + 1;
Expression<Func<int, int>> exprTree = x => x + 1;

A primeira linha produz um delegado, enquanto a segunda produz uma árvore de expressão.

lambdas são simplesmente açúcar sintático em um delegado.O compilador acaba convertendo lambdas em delegados.

São iguais, acredito:

Delegate delegate = x => "hi!";
Delegate delegate = delegate(object x) { return "hi";};

Um delegado é uma assinatura de função;algo como

delegate string MyDelegate(int param1);

O delegado não implementa um corpo.

O lambda é uma chamada de função que corresponde à assinatura do delegado.Para o delegado acima, você pode usar qualquer um dos seguintes;

(int i) => i.ToString();
(int i) => "ignored i";
(int i) => "Step " + i.ToString() + " of 10";

O Delegate type é mal nomeado;criando um objeto do tipo Delegate na verdade, cria uma variável que pode conter funções - sejam elas lambdas, métodos estáticos ou métodos de classe.

Um delegado é uma referência a um método com uma lista de parâmetros e tipo de retorno específicos.Pode ou não incluir um objeto.

Uma expressão lambda é uma forma de função anônima.

Está bastante claro que a questão era "qual é a diferença entre lambdas e anônimo delegados?" De todas as respostas aqui, apenas uma pessoa acertou - a principal diferença é que lambdas podem ser usados ​​para criar árvores de expressão, bem como delegados.

Você pode ler mais no MSDN: http://msdn.microsoft.com/en-us/library/bb397687.aspx

Os delegados são, na verdade, apenas digitação estrutural para funções.Você poderia fazer a mesma coisa com digitação nominal e implementar uma classe anônima que implemente uma interface ou classe abstrata, mas isso acaba sendo muito código quando apenas uma função é necessária.

Lambda vem da ideia de cálculo lambda da Igreja Alonzo na década de 1930.É uma forma anônima de criar funções.Eles se tornam especialmente úteis para compor funções

Portanto, embora alguns possam dizer que lambda é um açúcar sintático para delegados, eu diria que os delegados são uma ponte para facilitar as pessoas a usar lambdas em c#.

Um delegado é uma fila de ponteiros de função; invocar um delegado pode invocar vários métodos.Um lambda é essencialmente uma declaração de método anônima que pode ser interpretada de maneira diferente pelo compilador, dependendo do contexto em que é usada.

Você pode obter um delegado que aponta para a expressão lambda como um método convertendo-o em um delegado ou, se o passar como parâmetro para um método que espera um tipo de delegado específico, o compilador o converterá para você.Usando-o dentro de uma instrução LINQ, o lambda será traduzido pelo compilador em uma árvore de expressão em vez de simplesmente em um delegado.

A diferença realmente é que um lambda é uma maneira concisa de definir um método dentro de outra expressão, enquanto um delegado é um tipo de objeto real.

Lambdas são versões simplificadas de delegados.Eles têm algumas das propriedades de um fecho como delegados anônimos, mas também permitem o uso de digitação implícita.Um lambda como este:

something.Sort((x, y) => return x.CompareTo(y));

é muito mais conciso do que você pode fazer com um delegado:

something.Sort(sortMethod);
...

private int sortMethod(SomeType one, SomeType two)
{
    one.CompareTo(two)
}

Aqui está um exemplo que coloquei há algum tempo em meu blog coxo.Digamos que você queira atualizar um rótulo de um thread de trabalho.Tenho 4 exemplos de como atualizar esse rótulo de 1 para 50 usando delegados, delegados anon e 2 tipos de lambdas.

 private void button2_Click(object sender, EventArgs e) 
     { 
         BackgroundWorker worker = new BackgroundWorker(); 
         worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
         worker.RunWorkerAsync(); 
     } 

     private delegate void UpdateProgDelegate(int count); 
     private void UpdateText(int count) 
     { 
         if (this.lblTest.InvokeRequired) 
         { 
             UpdateProgDelegate updateCallBack = new UpdateProgDelegate(UpdateText); 
             this.Invoke(updateCallBack, new object[] { count }); 
         } 
         else 
         { 
             lblTest.Text = count.ToString(); 
         } 
     } 

     void worker_DoWork(object sender, DoWorkEventArgs e) 
     {   
         /* Old Skool delegate usage.  See above for delegate and method definitions */ 
         for (int i = 0; i < 50; i++) 
         { 
             UpdateText(i); 
             Thread.Sleep(50); 
         } 

         // Anonymous Method 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke((MethodInvoker)(delegate() 
             { 
                 lblTest.Text = i.ToString(); 
             })); 
             Thread.Sleep(50); 
         } 

         /* Lambda using the new Func delegate. This lets us take in an int and 
          * return a string.  The last parameter is the return type. so 
          * So Func<int, string, double> would take in an int and a string 
          * and return a double.  count is our int parameter.*/ 
         Func<int, string> UpdateProgress = (count) => lblTest.Text = count.ToString(); 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke(UpdateProgress, i); 
             Thread.Sleep(50); 
         } 

         /* Finally we have a totally inline Lambda using the Action delegate 
          * Action is more or less the same as Func but it returns void. We could 
          * use it with parameters if we wanted to like this: 
          * Action<string> UpdateProgress = (count) => lblT…*/ 
         for (int i = 0; i < 50; i++) 
         { 
             lblTest.Invoke((Action)(() => lblTest.Text = i.ToString())); 
             Thread.Sleep(50); 
         } 
     }

Presumo que sua pergunta diga respeito a c# e não a .NET, devido à ambiguidade de sua pergunta, pois o .NET não fica sozinho - ou seja, sem c# - compreensão de delegados e expressões lambda.

A (normal, em oposição aos chamados genérico delegados, cf. mais tarde) o delegado deve ser visto como uma espécie de c++ typedef de um tipo de ponteiro de função, por exemplo em c++:

R (*thefunctionpointer) ( T ) ;

typedef é o tipo thefunctionpointer que é o tipo de ponteiros para uma função que recebe um objeto do tipo T e retornando um objeto do tipo R.Você usaria assim:

thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T

onde thefunction seria uma função tomando um T e retornando um R.

Em c# você iria para

delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed

e você usaria assim:

thedelegate thedel = thefunction ;
R r = thedel ( t ) ; // where t is of type T

onde thefunction seria uma função tomando um T e retornando um R.Isto é para delegados, os chamados delegados normais.

Agora, você também tem delegados genéricos em c#, que são delegados genéricos, ou seja que são "modelados", por assim dizer, usando assim uma expressão c++.Eles são definidos assim:

public delegate TResult Func<in T, out TResult>(T arg);

E você pode usá-los assim:

Func<double, double> thefunctor = thefunction2; // call it a functor because it is
                                                // really as a functor that you should
                                                // "see" it
double y = thefunctor(2.0);

onde thefunction2 é uma função que toma como argumento e retorna um double.

Agora imagine que em vez de thefunction2 Eu gostaria de usar uma "função" que não está definida em nenhum lugar por enquanto, por uma instrução, e que nunca usarei mais tarde.Então c# nos permite usar o expressão desta função.Por expressão quero dizer a expressão "matemática" (ou funcional, para nos limitarmos aos programas), por exemplo:para um double x Eu vou associado o double x*x.Em matemática você escreve isso usando o símbolo de látex "\mapsto".Em c# a notação funcional foi emprestada: =>.Por exemplo :

Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not
                                                           // mandatory

(double x) => x * x é um expressão.Não é um tipo, enquanto os delegados (genéricos ou não) são.

Moralidade?No final, o que é um delegado (resp.delegado genérico), se não for um tipo de ponteiro de função (resp.tipo de ponteiro de função encapsulado + inteligente + genérico), hein?Algo mais !Ver esse e que.

Alguns básicos aqui."Delegado" é na verdade o nome de uma variável que contém uma referência a um método ou lambda

Este é um método anônimo -

(string testString) => { Console.WriteLine(testString); };

Como o método anônimo não tem nome, precisamos de um delegado no qual possamos atribuir ambos os métodos ou expressões.Por ex.

delegate void PrintTestString(string testString); // declare a delegate

PrintTestString print = (string testString) => { Console.WriteLine(testString); }; 
print();

O mesmo acontece com a expressão lambda.Geralmente precisamos de delegado para usá-los

s => s.Age > someValue && s.Age < someValue    // will return true/false

Podemos usar um delegado func para usar esta expressão.

Func< Student,bool> checkStudentAge = s => s.Age > someValue && s.Age < someValue ;

bool result = checkStudentAge ( Student Object);

Bem, a versão realmente simplificada é que lambda é apenas uma abreviação para uma função anônima.Um delegado pode fazer muito mais do que apenas funções anônimas:coisas como eventos, chamadas assíncronas e múltiplas cadeias de métodos.

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