В чем разница между лямбдами и делегатами в .NET Framework? - PullRequest
71 голосов
/ 16 сентября 2008

Мне часто задают этот вопрос, и я подумала, что хочу получить информацию о том, как лучше всего описать разницу.

Ответы [ 17 ]

1 голос
/ 16 сентября 2008

Делегат - это Очередь указателей функций, вызов делегата может вызывать несколько методов. Лямбда - это, по сути, объявление анонимного метода, которое может интерпретироваться компилятором по-разному, в зависимости от того, в каком контексте оно используется.

Вы можете получить делегат, который указывает на лямбда-выражение как метод, приведя его к делегату или передав его в качестве параметра методу, который ожидает определенный тип делегата, который компилятор применит для вас. Используя его внутри оператора LINQ, лямбда будет преобразована компилятором в дерево выражений, а не просто в делегат.

Разница действительно в том, что лямбда - это краткий способ определения метода внутри другого выражения, в то время как делегат является фактическим типом объекта.

1 голос
/ 16 сентября 2008

Делегаты - это просто структурная типизация функций. Вы могли бы сделать то же самое с именной типизацией и реализацией анонимного класса, который реализует интерфейс или абстрактный класс, но в итоге получается много кода, когда требуется только одна функция.

Лямбда происходит от идеи лямбда-исчисления церкви Алонзо в 1930-х годах. Это анонимный способ создания функций. Они становятся особенно полезными для составления функций

Так что, хотя некоторые могут сказать, что лямбда - это синтаксический сахар для делегатов, я бы сказал, что делегаты - это мост для облегчения лямбды в c #.

0 голосов
/ 16 сентября 2008

Вот пример, который я выложил некоторое время в своем хромом блоге. Скажем, вы хотите обновить метку из рабочего потока. У меня есть 4 примера того, как обновить эту метку с 1 до 50, используя делегаты, анон делегаты и 2 типа лямбд.

 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); 
         } 
     }
0 голосов
/ 16 сентября 2008

Лямбды - это упрощенные версии делегатов. У них есть некоторые свойства замыкания , подобные анонимным делегатам, но они также позволяют использовать неявную типизацию Лямбда, как это:

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

намного лаконичнее, чем то, что вы можете сделать с делегатом:

something.Sort(sortMethod);
...

private int sortMethod(SomeType one, SomeType two)
{
    one.CompareTo(two)
}
0 голосов
/ 21 ноября 2014

Я предполагаю, что ваш вопрос касается c #, а не .NET, из-за неоднозначности вашего вопроса, так как .NET не остается в одиночестве, то есть без c # - понимания делегатов и лямбда-выражений.

A ( normal , в отличие от так называемых универсальных делегатов, cf позже) делегата следует рассматривать как разновидность c ++ typedef тип указателя на функцию, например в c ++:

R (*thefunctionpointer) ( T ) ;

typedef - это тип thefunctionpointer, который является типом указателей на функцию, принимающую объект типа T и возвращающий объект типа R. Вы бы использовали это так:

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

, где thefunction - функция, принимающая T и возвращающая R.

В c # вы бы пошли на

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

и вы бы использовали его так:

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

где thefunction - функция, принимающая T и возвращающая R. Это для делегатов, так называемых обычных делегатов.

Теперь у вас также есть обобщенные делегаты в c #, которые являются обобщенными делегатами, , т.е. , которые, так сказать, «шаблонизированы», используя, таким образом, выражение c ++. Они определены так:

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

И вы можете использовать их так:

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);

, где thefunction2 - функция, принимающая в качестве аргумента и возвращающая double.

Теперь представьте, что вместо thefunction2 я хотел бы использовать «функцию», которая пока нигде не определена оператором, и которую я никогда не буду использовать позже. Тогда c # позволяет нам использовать выражение этой функции. Под выражением я подразумеваю его «математическое» (или функциональное, чтобы придерживаться программ) выражение, например: double x я буду ассоциировать double x*x. В математике вы пишете это, используя латексный символ "\ mapsto" . В c # функциональная запись была заимствована: =>. Например:

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

(double x) => x * x - это выражение . Это не тип, тогда как делегаты (общие или нет).

Мораль? В конце концов, что такое делегат (соответственно универсальный делегат), если не тип указателя функции (соответственно упакованный + умный + тип указателя универсальной функции), а? Что-то другое ! См. это и это .

0 голосов
/ 13 мая 2018

Некоторые основные здесь. «Делегат» - это имя переменной, которая содержит ссылку на метод или лямбду

Это анонимный метод -

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

Поскольку у анонимного метода нет имени, нам нужен делегат, в котором мы можем назначить оба метода или выражения. Например,

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

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

То же самое с лямбда-выражением. Обычно нам нужен делегат, чтобы использовать их

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

Мы можем использовать делегат func для использования этого выражения.

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

bool result = checkStudentAge ( Student Object);
0 голосов
/ 16 сентября 2008

Ну, очень упрощенная версия заключается в том, что лямбда - это просто сокращение для анонимной функции. Делегат может выполнять намного больше, чем просто анонимные функции: такие как события, асинхронные вызовы и несколько цепочек методов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...