it-swarm-vi.tech

Sự khác biệt giữa lambdas và đại biểu trong .NET Framework là gì?

Tôi được hỏi câu hỏi này rất nhiều và tôi nghĩ rằng tôi đã thu hút một số ý kiến ​​về cách mô tả sự khác biệt tốt nhất.

66
ScottKoon

Họ thực sự là hai điều rất khác nhau. "Delegate" thực sự là tên của một biến chứa tham chiếu đến một phương thức hoặc lambda và lambda là một phương thức không có tên vĩnh viễn.

Lambdas rất giống các phương pháp khác, ngoại trừ một vài khác biệt tinh tế.

  1. Một phương thức bình thường được định nghĩa trong một "câu lệnh" và được gắn với một tên vĩnh viễn, trong khi lambda được định nghĩa "trên đường bay" trong một "biểu thức" và không có tên vĩnh viễn.
  2. Một số lambdas có thể được sử dụng với cây biểu thức .NET, trong khi các phương thức thì không thể.

Một đại biểu được định nghĩa như thế này:

delegate Int32 BinaryIntOp(Int32 x, Int32 y);

Một biến loại BinaryIntOp có thể có một phương thức hoặc labmda được gán cho nó, miễn là chữ ký giống nhau: hai đối số Int32 và trả về Int32.

Một lambda có thể được định nghĩa như thế này:

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

Một điều cần lưu ý là mặc dù các loại Func và Action chung thường được coi là "loại lambda", chúng cũng giống như bất kỳ đại biểu nào khác. Điều thú vị ở họ là về cơ bản họ xác định tên cho bất kỳ loại đại biểu nào bạn có thể cần (tối đa 4 tham số, mặc dù bạn chắc chắn có thể thêm nhiều tên của riêng mình). Vì vậy, nếu bạn đang sử dụng nhiều loại đại biểu, nhưng không quá một lần, bạn có thể tránh làm lộn xộn mã của mình với các khai báo đại biểu bằng cách sử dụng Func và Action.

Dưới đây là một minh họa về cách Func và Action "không chỉ dành cho lambdas":

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

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

Một điều hữu ích khác cần biết là các loại đại biểu (không phải bản thân các phương thức) có cùng chữ ký nhưng các tên khác nhau sẽ không được đặt ngầm cho nhau. Điều này bao gồm các đại biểu Func và Action. Tuy nhiên, nếu chữ ký giống hệt nhau, bạn có thể phân biệt rõ ràng giữa chúng.

Đi thêm một dặm .... Trong các chức năng C # rất linh hoạt, với việc sử dụng lambdas và đại biểu. Nhưng C # không có "chức năng hạng nhất". Bạn có thể sử dụng tên của hàm được gán cho biến đại biểu để tạo một đối tượng đại diện cho hàm đó. Nhưng nó thực sự là một thủ thuật biên dịch. Nếu bạn bắt đầu một câu lệnh bằng cách viết tên hàm theo sau là dấu chấm (nghĩa là cố gắng truy cập thành viên vào chính hàm đó), bạn sẽ thấy không có thành viên nào ở đó để tham khảo. Ngay cả những người từ Object. Điều này ngăn lập trình viên thực hiện những điều hữu ích (và có khả năng nguy hiểm tất nhiên) như thêm các phương thức mở rộng có thể được gọi trên bất kỳ chức năng nào. Điều tốt nhất bạn có thể làm là mở rộng lớp Delegate, điều này chắc chắn cũng hữu ích, nhưng không nhiều lắm.

Cập nhật: Cũng xem Câu trả lời của Karg minh họa sự khác biệt giữa các đại biểu ẩn danh so với phương thức & lambdas.

Cập nhật 2: James Hart làm cho một điều quan trọng, mặc dù rất kỹ thuật, lưu ý rằng lambdas và đại biểu không phải là các thực thể .NET (tức là CLR không có khái niệm về đại biểu hoặc lambda), mà là các cấu trúc ngôn ngữ và khung.

79
Chris Ammerman

Câu hỏi hơi mơ hồ, điều này giải thích sự chênh lệch lớn trong các câu trả lời bạn nhận được.

Bạn thực sự đã hỏi sự khác biệt giữa lambdas và đại biểu trong khung .NET; đó có thể là một trong số nhiều thứ Bạn đang hỏi tôi sao:

  • Sự khác biệt giữa biểu thức lambda và đại biểu ẩn danh trong ngôn ngữ C # (hoặc VB.NET) là gì?

  • Sự khác biệt giữa các đối tượng System.Linq.Expressions.LambdaExpression và các đối tượng System.Delegate trong .NET 3.5 là gì?

  • Hoặc một cái gì đó ở đâu đó giữa hoặc xung quanh những thái cực đó?

Một số người dường như đang cố gắng cung cấp cho bạn câu trả lời cho câu hỏi 'sự khác biệt giữa các biểu thức C # Lambda và .NET System.Delegate là gì?', Điều này không có ý nghĩa gì nhiều.

Bản thân .NET framework không hiểu các khái niệm về đại biểu ẩn danh, biểu thức lambda hoặc bao đóng - đó là tất cả những thứ được xác định bởi thông số kỹ thuật ngôn ngữ. Hãy suy nghĩ về cách trình biên dịch C # chuyển định nghĩa của một phương thức ẩn danh thành một phương thức trên một lớp được tạo với các biến thành viên để giữ trạng thái đóng; đối với .NET, không có gì ẩn danh về đại biểu; nó chỉ là ẩn danh cho lập trình viên C # viết nó. Điều đó cũng đúng với biểu thức lambda được gán cho loại đại biểu.

Những gì .NETKH&OCIRC;NGhiểu là ý tưởng của đại biểu - một loại mô tả chữ ký phương thức, các trường hợp thể hiện các cuộc gọi bị ràng buộc với các phương thức cụ thể trên các đối tượng cụ thể hoặc các cuộc gọi không liên kết đến một phương thức cụ thể loại có thể được gọi đối với bất kỳ đối tượng nào thuộc loại đó, trong đó phương thức đã nói tuân thủ chữ ký đã nói. Những kiểu như vậy đều được kế thừa từ System.Delegate.

.NET 3.5 cũng giới thiệu không gian tên System.Linq.Expressions, chứa các lớp để mô tả các biểu thức mã - và do đó cũng có thể biểu thị các lệnh gọi bị ràng buộc hoặc không gắn kết với các phương thức trên các loại hoặc đối tượng cụ thể. Các phiên bản LambdaExpression sau đó có thể được biên dịch thành các đại biểu thực tế (theo đó một phương thức động dựa trên cấu trúc của biểu thức được mã hóa và một con trỏ ủy nhiệm cho nó được trả về).

Trong C #, bạn có thể tạo các thể hiện của các loại System.Expressions.Expression bằng cách gán một biểu thức lambda cho một biến của loại đã nói, sẽ tạo ra mã thích hợp để xây dựng biểu thức khi chạy.

Tất nhiên, nếu bạn đã hỏi sự khác biệt giữa biểu thức lambda và phương thức ẩn danh trong C #, thì tất cả điều này là khá nhiều không phù hợp, và trong trường hợp đó, sự khác biệt chính là ngắn gọn, đối với các đại biểu ẩn danh khi bạn không quan tâm đến các tham số và không có kế hoạch trả về một giá trị và hướng tới lambdas khi bạn muốn loại tham số được suy ra và các kiểu trả về.

Và biểu thức lambda hỗ trợ tạo biểu thức.

27
James Hart

Một điểm khác biệt là một đại biểu ẩn danh có thể bỏ qua các tham số trong khi lambda phải khớp với chữ ký chính xác. Được:

public delegate string TestDelegate(int i);

public void Test(TestDelegate d)
{}

bạn có thể gọi nó theo bốn cách sau (lưu ý rằng dòng thứ hai có đại biểu ẩn danh không có bất kỳ tham số nào):

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

Bạn không thể truyền vào biểu thức lambda không có tham số hoặc phương thức không có tham số. Những thứ này không được phép:

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

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

Các đại biểu tương đương với các con trỏ hàm/con trỏ phương thức/gọi lại (hãy chọn) và lambdas là các hàm ẩn danh được đơn giản hóa khá nhiều. Ít nhất đó là những gì tôi nói với mọi người.

13
Dan Shield

Tôi không có nhiều kinh nghiệm về vấn đề này, nhưng theo cách tôi mô tả thì đó là một đại biểu là một hàm bao quanh bất kỳ chức năng nào, trong khi biểu thức lambda tự nó là một hàm ẩn danh.

3
chessguy

Một đại biểu luôn luôn chỉ là một con trỏ hàm. Một lambda có thể biến thành một đại biểu, nhưng nó cũng có thể biến thành cây biểu thức LINQ. Ví dụ,

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

Dòng đầu tiên tạo ra một đại biểu, trong khi dòng thứ hai tạo ra một cây biểu thức.

3
Curt Hagenlocher

Một đại biểu là một tham chiếu đến một phương thức với một danh sách tham số cụ thể và kiểu trả về. Nó có thể hoặc không bao gồm một đối tượng.

Biểu thức lambda là một dạng của hàm ẩn danh.

2
Peter Ritchie

lambdas chỉ đơn giản là cú pháp đường trên một đại biểu. Trình biên dịch kết thúc chuyển đổi lambdas thành đại biểu.

Đây là như nhau, tôi tin rằng:

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

Một đại biểu là một chữ ký chức năng; cái gì đó như 

delegate string MyDelegate(int param1);

Các đại biểu không thực hiện một cơ quan. 

Lambda là một cuộc gọi chức năng phù hợp với chữ ký của đại biểu. Đối với đại biểu trên, bạn có thể sử dụng bất kỳ;

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

Mặc dù vậy, loại Delegate được đặt tên xấu; tạo một đối tượng kiểu Delegate thực sự tạo ra một biến có thể chứa các hàm - có thể là lambdas, phương thức tĩnh hoặc phương thức lớp.

2
Steve Cooper

Một điều khá rõ ràng là câu hỏi có nghĩa là "sự khác biệt giữa lambdas và nặc danh đại biểu?" Trong số tất cả các câu trả lời ở đây chỉ có một người hiểu đúng - sự khác biệt chính là lambdas có thể được sử dụng để tạo cây biểu thức cũng như các đại biểu.

Bạn có thể đọc thêm trên MSDN: http://msdn.Microsoft.com/en-us/l Library/bb397687.aspx

2
Philip Beber

Một đại biểu là một hàng đợi của các con trỏ hàm, việc gọi một đại biểu có thể gọi nhiều phương thức. Lambda về cơ bản là một khai báo phương thức ẩn danh có thể được trình biên dịch diễn giải khác nhau, tùy thuộc vào bối cảnh nó được sử dụng như thế nào.

Bạn có thể lấy một đại biểu trỏ đến biểu thức lambda như một phương thức bằng cách chuyển nó thành một đại biểu hoặc nếu truyền nó dưới dạng tham số cho một phương thức mong đợi một loại đại biểu cụ thể mà trình biên dịch sẽ truyền cho bạn. Sử dụng nó bên trong một câu lệnh LINQ, lambda sẽ được trình biên dịch dịch thành một cây biểu thức thay vì chỉ đơn giản là một ủy nhiệm.

Sự khác biệt thực sự là lambda là một cách ngắn gọn để định nghĩa một phương thức bên trong một biểu thức khác, trong khi một đại biểu là một loại đối tượng thực tế.

1
justin.m.chase

Các đại biểu thực sự chỉ là cấu trúc gõ cho các chức năng. Bạn có thể làm điều tương tự với việc gõ danh nghĩa và thực hiện một lớp ẩn danh thực hiện một giao diện hoặc lớp trừu tượng, nhưng cuối cùng lại có rất nhiều mã khi chỉ cần một hàm.

Lambda xuất phát từ ý tưởng tính toán lambda của Nhà thờ Alonzo vào những năm 1930. Đó là một cách ẩn danh để tạo chức năng. Chúng trở nên đặc biệt hữu ích cho việc soạn thảo các hàm

Vì vậy, trong khi một số người có thể nói lambda là đường cú pháp cho các đại biểu, tôi sẽ nói rằng các đại biểu là cầu nối để đưa mọi người vào lambdas trong c #.

1
Steve g

Tôi cho rằng câu hỏi của bạn liên quan đến c # chứ không phải .NET, vì sự mơ hồ của câu hỏi của bạn, vì .NET không đơn độc - nghĩa là không có c # - hiểu về các đại biểu và biểu thức lambda.

Một đại biểu (normal, đối lập với cái gọi là đại biểu generic, đại biểu cf sau) nên được xem như một loại c ++ typedef của loại con trỏ hàm, ví dụ như trong c ++:

R (*thefunctionpointer) ( T ) ;

typedef là loại thefunctionpointer là loại con trỏ tới hàm lấy một đối tượng thuộc loại T và trả về một đối tượng thuộc loại R. Bạn sẽ sử dụng nó như thế này:

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

trong đó thefunction sẽ là một hàm lấy T và trả về R.

Trong c # bạn sẽ đi

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

và bạn sẽ sử dụng nó như thế này:

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

trong đó thefunction sẽ là một hàm lấy T và trả về R. Điều này là dành cho các đại biểu, vì vậy được gọi là đại biểu bình thường.

Bây giờ, bạn cũng có các đại biểu chung trong c #, là các đại biểu chung chung, tức là được "templated" để nói, sử dụng biểu thức c ++. Chúng được định nghĩa như thế này:

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

Và bạn có thể sử dụng chúng như thế này:

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

trong đó thefunction2 là một hàm lấy làm đối số và trả về double.

Bây giờ hãy tưởng tượng rằng thay vì thefunction2 tôi muốn sử dụng một "hàm" không được xác định cho đến bây giờ, bằng một câu lệnh và tôi sẽ không bao giờ sử dụng sau này. Sau đó, c # cho phép chúng ta sử dụng biểu thức của hàm này. Theo biểu thức, tôi có nghĩa là biểu thức "toán học" (hoặc chức năng, để bám sát các chương trình) của nó, ví dụ: với một double x tôi sẽ liên kếtdoublex*x. Trong toán học, bạn viết điều này bằng cách sử dụng biểu tượng latex "\ mapsto" . Trong c #, ký hiệu chức năng đã được mượn: =>. Ví dụ :

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

(double x) => x * x là một biểu thức . Nó không phải là một loại, trong khi các đại biểu (chung chung hoặc không) là.

Đạo đức ? Cuối cùng, một đại biểu (đại biểu chung) là gì, nếu không phải là một loại con trỏ hàm (resp. Bọc + smart + loại con trỏ hàm chung), hả? Thứ gì khác ! Xem cái nàycái đó .

Đây là một ví dụ tôi đưa ra một lúc trên blog khập khiễng của tôi. Giả sử bạn muốn cập nhật nhãn từ luồng công nhân. Tôi đã có 4 ví dụ về cách cập nhật nhãn đó từ 1 đến 50 bằng cách sử dụng đại biểu, đại biểu anon và 2 loại 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); 
         } 
     }
0
Echostorm

Một số cơ bản ở đây. [.___.] "Delegate" thực sự là tên của một biến chứa tham chiếu đến một phương thức hoặc lambda

Đây là một phương thức ẩn danh - [.__.] (Chuỗi testString) => {Console.WriteLine (testString); };

Vì phương thức ẩn danh không có bất kỳ tên nào, chúng tôi cần một đại biểu trong đó chúng tôi có thể gán cả hai phương thức hoặc biểu thức này. Ví dụ.

ủy nhiệm void PrintTestString (chuỗi testString); // khai báo một đại biểu

PrintTestString print = (chuỗi testString) => {Console.WriteLine (testString); }; in();


Tương tự với biểu thức lambda. Thông thường chúng ta cần đại biểu để sử dụng chúng

s => s.Age> someValue && s.Age <someValue // sẽ trả về true/false

Chúng ta có thể sử dụng một đại biểu func để sử dụng biểu thức này.

Func <Sinh viên, bool> checkStudentAge = s => s.Age> someValue && s.Age <someValue;

bool result = checkStudentAge (Đối tượng sinh viên);

0
Yogesh Prajapati

Lambdas là phiên bản đơn giản hóa của các đại biểu. Họ có một số thuộc tính của một bao đóng như đại biểu ẩn danh, nhưng cũng cho phép bạn sử dụng cách gõ ngụ ý. Một lambda như thế này:

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

ngắn gọn hơn nhiều so với những gì bạn có thể làm với một đại biểu:

something.Sort(sortMethod);
...

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