por que as pessoas tornam sua pergunta tão complicada? Basta responder o que é um delegado e o que é um lambda. Dê o máximo de explicação possível e deixe-o escolher o que for apropriado para ele.
Imir Hoxha
Respostas:
96
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 lambda é um método sem um nome permanente.
Lambdas são muito parecidos com outros métodos, exceto por algumas diferenças sutis.
Um método normal é definido em uma "instrução" e vinculado a um nome permanente, enquanto um lambda é definido "instantaneamente" em uma "expressão" e não tem nome permanente.
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 observar é que, embora os tipos genéricos Func e Action sejam frequentemente considerados "tipos lambda", eles são como quaisquer outros delegados. A coisa boa sobre eles é que eles essencialmente definem um nome para qualquer tipo de delegado que você possa precisar (até 4 parâmetros, embora você certamente possa adicionar outros). Portanto, se você estiver usando uma grande variedade de tipos de delegado, mas não mais de uma vez, pode evitar confundir seu código com declarações de delegado usando Func e Action.
Aqui está uma ilustração de como Func e Action são "não apenas para lambdas":
Outra coisa útil a saber é que os tipos de delegado (não os métodos em si) com a mesma assinatura, mas com nomes diferentes, não serão convertidos implicitamente entre si. Isso inclui os delegados Func e Action. No entanto, se a assinatura for idêntica, você pode converter explicitamente entre eles.
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 criar essencialmente 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 por um ponto (ou seja, tente fazer o acesso de membro na própria função), você descobrirá que não há membros para fazer 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, que certamente também é útil, mas não tanto.
Atualização: veja também a resposta de Karg ilustrando a diferença entre delegados anônimos e 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 sim estruturas e construções de linguagem.
Boa explicação. Embora eu ache que você quer dizer "funções de primeira classe", não "objetos de primeira classe". :)
ibz
1
Você está certo. Eu tive a frase estruturada de forma diferente durante a escrita ("funções C # não são realmente objetos de primeira classe") e esqueci de mudar isso. Obrigado!
Chris Ammerman,
Um método normal é definido em uma "instrução". Uma instrução é uma ação na seqüência de um programa imperativo, possivelmente baseada em uma expressão. A definição de um método não é uma estrutura gramatical diferente? A definição do método não está listada em docs.microsoft.com/en-us/dotnet/csharp/tour-of-csharp/…
Max Barraclough
32
A pergunta é um pouco ambígua, o que explica a grande disparidade de respostas que você está obtendo.
Na verdade, você perguntou qual é a diferença entre lambdas e delegados no .NET framework; isso pode ser uma de 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 em torno desses 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 encerramentos - todas essas coisas são definidas por especificações de 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 .NET, não há nada anônimo sobre o delegado; é apenas anônimo para o programador C # que o escreveu. Isso é igualmente verdadeiro para uma expressão lambda atribuída a um tipo delegado.
O que o .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 particular em um tipo particular que pode ser invocado qualquer objeto desse tipo, em que o referido método adere à referida assinatura. Todos esses tipos são herdados de System.Delegate.
.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 representar chamadas vinculadas ou não a métodos em tipos ou objetos específicos. As instâncias LambdaExpression podem então ser compiladas em delegados reais (por meio do qual um método dinâmico baseado na estrutura da expressão é codificado e um ponteiro de delegado é retornado).
Em C #, você pode produzir instâncias de tipos System.Expressions.Expression atribuindo uma expressão lambda a uma variável desse tipo, que produzirá o código apropriado para construir a expressão em tempo de execução.
Claro, se você estivesse perguntando qual é a diferença entre expressões lambda e métodos anônimos em C #, afinal, tudo isso é praticamente irrelevante e, nesse caso, a principal diferença é a brevidade, que tende a delegados anônimos quando você não Não se preocupe com os parâmetros e não planeje retornar um valor, e em direção aos lambdas quando quiser parâmetros inferidos de tipo e tipos de retorno.
E as expressões lambda suportam a geração de expressões.
Ótima informação! Você me inspirou a acender o refletor e olhar para o IL. Eu não sabia que lambdas resultavam em classes geradas, mas faz todo o sentido agora que penso nisso.
Chris Ammerman
20
Uma diferença é que um delegado anônimo pode omitir parâmetros enquanto um lambda deve corresponder à assinatura exata. Dado:
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 signatureprivatestringD2()
{
return String.Empty;
}
Delegados são equivalentes a ponteiros de função / ponteiros de método / retornos de chamada (faça sua escolha), e lambdas são funções anônimas bastante simplificadas. Pelo menos é o que digo às pessoas.
Exatamente! Não há diferença". Eles são duas coisas inerentemente diferentes.
ibz
3
Não tenho muita experiência com isso, mas a forma como eu descreveria é que um delegado é um invólucro 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ão 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.
Isso é verdade, mas a diferença entre eles é que são dois conceitos completamente diferentes . É como comparar maçãs e laranjas. Veja a resposta de Dan Shield.
ibz
2
lambdas são simplesmente açúcar sintático em um delegado. O compilador acaba convertendo lambdas em delegados.
O Delegatetipo é mal nomeado, no entanto; criar um objeto do tipo Delegatena verdade cria uma variável que pode conter funções - sejam lambdas, métodos estáticos ou métodos de classe.
Quando você cria uma variável do tipo MyDelegate, esse não é realmente o tipo de tempo de execução. O tipo de tempo de execução é Delegado. Existem truques de compilador envolvidos em como os delegados, lambdas e árvores de expressão são compilados, o que eu acho que faz com que o código implique coisas que não são verdadeiras.
Chris Ammerman,
2
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.
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ônimo que pode ser interpretada pelo compilador de maneira diferente, dependendo do contexto em que é usado.
Você pode obter um delegado que aponta para a expressão lambda como um método, convertendo-o em um delegado ou, se passando-o como um parâmetro para um método que espera um tipo específico de delegado, o compilador o lançará 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 um delegado.
A diferença realmente é que lambda é uma maneira concisa de definir um método dentro de outra expressão, enquanto um delegado é um tipo de objeto real.
É bastante claro que a pergunta era "qual é a diferença entre lambdas e delegados anônimos ?" 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.
Delegados são, na verdade, apenas tipagem estrutural para funções. Você poderia fazer a mesma coisa com a digitação nominal e implementação de uma classe anônima que implementa uma interface ou classe abstrata, mas isso acaba sendo muito código quando apenas uma função é necessária.
Lambda vem da ideia do cálculo lambda da Igreja Alonzo nos anos 1930 É uma forma anônima de criar funções. Eles se tornam especialmente úteis para compor funções
Então, embora alguns possam dizer que lambda é um açúcar sintático para delegados, eu diria que delegados são uma ponte para facilitar as pessoas em lambdas em c #.
Lambdas são versões simplificadas de delegados. Eles têm algumas das propriedades de um encerramento, como delegados anônimos, mas também permitem que você use a digitação implícita. Um lambda como este:
something.Sort((x, y) => return x.CompareTo(y));
é muito mais conciso do que o que você pode fazer com um delegado:
Você quer dizer que lambdas são como métodos anônimos simplificados (não delegados). Como métodos (anônimos ou não), eles podem ser atribuídos a uma variável delegada.
Lucas
0
Aqui está um exemplo que coloquei por um tempo no meu blog coxo. Digamos que você queira atualizar um rótulo de um thread de trabalho. Eu tenho 4 exemplos de como atualizar esse rótulo de 1 para 50 usando delegados, delegados anon e 2 tipos de lambdas.
privatevoidbutton2_Click(object sender, EventArgs e)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += new DoWorkEventHandler(worker_DoWork);
worker.RunWorkerAsync();
}
privatedelegatevoidUpdateProgDelegate(int count);
privatevoidUpdateText(int count)
{
if (this.lblTest.InvokeRequired)
{
UpdateProgDelegate updateCallBack = new UpdateProgDelegate(UpdateText);
this.Invoke(updateCallBack, newobject[] { count });
}
else
{
lblTest.Text = count.ToString();
}
}
voidworker_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);
}
}
Suponho que sua pergunta se refere ao c # e não ao .NET, por causa da ambigüidade da sua pergunta, já que o .NET não consegue sozinho - isto é, sem c # - compreensão de delegados e expressões lambda.
Um delegado ( normal , em oposição aos chamados delegados genéricos , cf mais tarde) deve ser visto como uma espécie de c ++ typedefde um tipo de ponteiro de função, por exemplo em c ++:
R (*thefunctionpointer) ( T ) ;
typedef é o tipo thefunctionpointerque é o tipo de ponteiros para uma função pegando um objeto do tipo Te retornando um objeto do tipo R. Você o usaria assim:
thefunctionpointer = &thefunction ;
R r = (*thefunctionpointer) ( t ) ; // where t is of type T
onde thefunctionseria uma função tomando a Te retornando um R.
Em c # você iria para
delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed
e você o usaria assim:
thedelegate thedel = thefunction ;
R r = thedel ( t ) ; // where t is of type T
onde thefunctionseria uma função tomando a Te retornando um R. Isso é para delegados, os chamados delegados normais.
Agora, você também tem delegados genéricos em c #, que são delegados genéricos, ou seja , "modelados" por assim dizer, usando, portanto, uma expressão c ++. Eles são definidos assim:
Func<double, double> thefunctor = thefunction2; // call it a functor because it is// really as a functor that you should// "see" itdouble y = thefunctor(2.0);
onde thefunction2é uma função tomando como argumento e retornando a double.
Agora imagine que em vez de thefunction2eu gostaria de usar uma "função" que não está definida em nenhum lugar por agora, por uma instrução, e que nunca usarei mais tarde. Então, c # nos permite usar a expressão dessa função. Por expressão que significa o "matemático" (ou funcional, para furar a programas) expressão dela, por exemplo: a uma double xeu vou associar o doublex*x. Em matemática, você escreve isso usando o símbolo de látex "\ mapsto" . Em c # a notação funcional foi emprestado: =>. Por exemplo :
Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not// mandatory
(double x) => x * xé uma 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), senão um tipo de ponteiro de função (resp. Empacotado + inteligente + tipo de ponteiro de função genérico), hein? Algo mais ! Veja isso e aquilo .
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 várias cadeias de métodos.
lambdas podem ser usados como manipuladores de eventos; button.Click + = (sender, eventArgs) => {MessageBox.Show ("Click"); } e chamado de forma assíncrona new System.Threading.Thread (() => Console.Write ("Executado em um thread")). Start ();
Respostas:
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 lambda é um método sem um nome permanente.
Lambdas são muito parecidos com outros métodos, exceto por algumas diferenças sutis.
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:
Outra coisa a observar é que, embora os tipos genéricos Func e Action sejam frequentemente considerados "tipos lambda", eles são como quaisquer outros delegados. A coisa boa sobre eles é que eles essencialmente definem um nome para qualquer tipo de delegado que você possa precisar (até 4 parâmetros, embora você certamente possa adicionar outros). Portanto, se você estiver usando uma grande variedade de tipos de delegado, mas não mais de uma vez, pode evitar confundir seu código com declarações de delegado usando Func e Action.
Aqui está uma ilustração de como Func e Action são "nã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 de delegado (não os métodos em si) com a mesma assinatura, mas com nomes diferentes, não serão convertidos implicitamente entre si. Isso inclui os delegados Func e Action. No entanto, se a assinatura for idêntica, você pode converter explicitamente entre eles.
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 criar essencialmente 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 por um ponto (ou seja, tente fazer o acesso de membro na própria função), você descobrirá que não há membros para fazer 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, que certamente também é útil, mas não tanto.
Atualização: veja também a resposta de Karg ilustrando a diferença entre delegados anônimos e 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 sim estruturas e construções de linguagem.
fonte
A pergunta é um pouco ambígua, o que explica a grande disparidade de respostas que você está obtendo.
Na verdade, você perguntou qual é a diferença entre lambdas e delegados no .NET framework; isso pode ser uma de 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 em torno desses 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 encerramentos - todas essas coisas são definidas por especificações de 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 .NET, não há nada anônimo sobre o delegado; é apenas anônimo para o programador C # que o escreveu. Isso é igualmente verdadeiro para uma expressão lambda atribuída a um tipo delegado.
O que o .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 particular em um tipo particular que pode ser invocado qualquer objeto desse tipo, em que o referido método adere à referida assinatura. Todos esses tipos são herdados de System.Delegate.
.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 representar chamadas vinculadas ou não a métodos em tipos ou objetos específicos. As instâncias LambdaExpression podem então ser compiladas em delegados reais (por meio do qual um método dinâmico baseado na estrutura da expressão é codificado e um ponteiro de delegado é retornado).
Em C #, você pode produzir instâncias de tipos System.Expressions.Expression atribuindo uma expressão lambda a uma variável desse tipo, que produzirá o código apropriado para construir a expressão em tempo de execução.
Claro, se você estivesse perguntando qual é a diferença entre expressões lambda e métodos anônimos em C #, afinal, tudo isso é praticamente irrelevante e, nesse caso, a principal diferença é a brevidade, que tende a delegados anônimos quando você não Não se preocupe com os parâmetros e não planeje retornar um valor, e em direção aos lambdas quando quiser parâmetros inferidos de tipo e tipos de retorno.
E as expressões lambda suportam a geração de expressões.
fonte
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 parâmetros):
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; }
fonte
Delegados são equivalentes a ponteiros de função / ponteiros de método / retornos de chamada (faça sua escolha), e lambdas são funções anônimas bastante simplificadas. Pelo menos é o que digo às pessoas.
fonte
Não tenho muita experiência com isso, mas a forma como eu descreveria é que um delegado é um invólucro em torno de qualquer função, enquanto uma expressão lambda é em si uma função anônima.
fonte
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ão 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.
fonte
lambdas são simplesmente açúcar sintático em um delegado. O compilador acaba convertendo lambdas em delegados.
São os mesmos, creio:
Delegate delegate = x => "hi!"; Delegate delegate = delegate(object x) { return "hi";};
fonte
Delegate
'delegado', que é uma palavra-chave.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;
(int i) => i.ToString(); (int i) => "ignored i"; (int i) => "Step " + i.ToString() + " of 10";
O
Delegate
tipo é mal nomeado, no entanto; criar um objeto do tipoDelegate
na verdade cria uma variável que pode conter funções - sejam lambdas, métodos estáticos ou métodos de classe.fonte
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.
fonte
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ônimo que pode ser interpretada pelo compilador de maneira diferente, dependendo do contexto em que é usado.
Você pode obter um delegado que aponta para a expressão lambda como um método, convertendo-o em um delegado ou, se passando-o como um parâmetro para um método que espera um tipo específico de delegado, o compilador o lançará 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 um delegado.
A diferença realmente é que lambda é uma maneira concisa de definir um método dentro de outra expressão, enquanto um delegado é um tipo de objeto real.
fonte
É bastante claro que a pergunta era "qual é a diferença entre lambdas e delegados anônimos ?" 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
fonte
Delegados são, na verdade, apenas tipagem estrutural para funções. Você poderia fazer a mesma coisa com a digitação nominal e implementação de uma classe anônima que implementa uma interface ou classe abstrata, mas isso acaba sendo muito código quando apenas uma função é necessária.
Lambda vem da ideia do cálculo lambda da Igreja Alonzo nos anos 1930 É uma forma anônima de criar funções. Eles se tornam especialmente úteis para compor funções
Então, embora alguns possam dizer que lambda é um açúcar sintático para delegados, eu diria que delegados são uma ponte para facilitar as pessoas em lambdas em c #.
fonte
Alguns básicos aqui. "Delegate" é 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 nenhum nome, precisamos de um delegado no qual possamos atribuir ambos os métodos ou expressões. Para Ex.
delegate void PrintTestString(string testString); // declare a delegate PrintTestString print = (string testString) => { Console.WriteLine(testString); }; print();
Mesmo com a expressão lambda. Normalmente, 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);
fonte
Lambdas são versões simplificadas de delegados. Eles têm algumas das propriedades de um encerramento, como delegados anônimos, mas também permitem que você use a digitação implícita. Um lambda como este:
something.Sort((x, y) => return x.CompareTo(y));
é muito mais conciso do que o que você pode fazer com um delegado:
something.Sort(sortMethod); ... private int sortMethod(SomeType one, SomeType two) { one.CompareTo(two) }
fonte
Aqui está um exemplo que coloquei por um tempo no meu blog coxo. Digamos que você queira atualizar um rótulo de um thread de trabalho. Eu 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); } }
fonte
Suponho que sua pergunta se refere ao c # e não ao .NET, por causa da ambigüidade da sua pergunta, já que o .NET não consegue sozinho - isto é, sem c # - compreensão de delegados e expressões lambda.
Um delegado ( normal , em oposição aos chamados delegados genéricos , cf mais tarde) deve ser visto como uma espécie de c ++
typedef
de um tipo de ponteiro de função, por exemplo em c ++:typedef é o tipo
thefunctionpointer
que é o tipo de ponteiros para uma função pegando um objeto do tipoT
e retornando um objeto do tipoR
. Você o usaria assim:thefunctionpointer = &thefunction ; R r = (*thefunctionpointer) ( t ) ; // where t is of type T
onde
thefunction
seria uma função tomando aT
e retornando umR
.Em c # você iria para
delegate R thedelegate( T t ) ; // and yes, here the identifier t is needed
e você o usaria assim:
thedelegate thedel = thefunction ; R r = thedel ( t ) ; // where t is of type T
onde
thefunction
seria uma função tomando aT
e retornando umR
. Isso é para delegados, os chamados delegados normais.Agora, você também tem delegados genéricos em c #, que são delegados genéricos, ou seja , "modelados" por assim dizer, usando, portanto, 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 tomando como argumento e retornando adouble
.Agora imagine que em vez de
thefunction2
eu gostaria de usar uma "função" que não está definida em nenhum lugar por agora, por uma instrução, e que nunca usarei mais tarde. Então, c # nos permite usar a expressão dessa função. Por expressão que significa o "matemático" (ou funcional, para furar a programas) expressão dela, por exemplo: a umadouble x
eu vou associar odouble
x*x
. Em matemática, você escreve isso usando o símbolo de látex "\ mapsto" . Em c # a notação funcional foi emprestado:=>
. Por exemplo :Func<double, double> thefunctor = ( (double x) => x * x ); // outer brackets are not // mandatory
(double x) => x * x
é uma 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), senão um tipo de ponteiro de função (resp. Empacotado + inteligente + tipo de ponteiro de função genérico), hein? Algo mais ! Veja isso e aquilo .
fonte
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 várias cadeias de métodos.
fonte