2009-02-03 35 views
24

Tôi tò mò tại sao C# cho phép tôi bỏ qua các tham số ủy nhiệm trong một số trường hợp nhưng không phải là các thông số khác.Tôi có thể bỏ qua các tham số ủy nhiệm bằng cú pháp lambda không?

Đối với trường hợp này được phép:

Action<int> action = delegate { Console.WriteLine("delegate"); }; 

nhưng đây không phải là:

Action<int> action =() => Console.WriteLine("lambda"); 

Có cách nào để khởi tạo một delegate và bỏ qua các thông số sử dụng một lambda? Tôi biết rằng tôi có thể thêm một tham số duy nhất vào lambda và sửa chữa dòng trước nhưng đây là một câu hỏi học thuật liên quan đến trình biên dịch và tại sao hoặc cách thức hoạt động của nó.

Trả lời

17

Tôi tin rằng mẫu đầu tiên của bạn thực sự tạo ra một chức năng ẩn danh có khả năng thực hiện trên nhiều chữ ký khác nhau mà thân thể là câu lệnh đơn Console.WriteLine.... Bởi vì nó có thể phù hợp với chữ ký khác nhau, nó không gây ra một vấn đề. Trong mẫu thứ hai, cú pháp lambda tự định nghĩa một hàm không có tham số nào với cùng một phần tử. Rõ ràng sau này là không phù hợp với hành động được xác định để bạn có được lỗi.

C# Anonymous Method Reference

Có một trường hợp trong đó một phương pháp vô danh cung cấp chức năng không tìm thấy trong lambda biểu thức. Các phương thức ẩn danh cho phép bạn bỏ qua danh sách tham số và điều này có nghĩa là một phương thức ẩn danh có thể được chuyển đổi thành các đại biểu có một số chữ ký . Đây không phải là có thể với các biểu thức lambda.

+1

Cho dù điều này là đúng hay không phụ thuộc vào cách bạn đọc câu trả lời. IL được tạo ra là * chắc chắn * chỉ cho một phương thức lấy một int. Trình biên dịch * có * để biết loại thời gian biên dịch nó đang cố gắng chuyển đổi nó thành - nếu bạn thay đổi chữ ký của hành động thành "Ủy quyền", bạn sẽ nhận được một lỗi biên dịch thời gian. –

+0

Ý tôi là (và tôi nghĩ) là bỏ qua danh sách tham số từ đại biểu trong mẫu đầu tiên, trình biên dịch "điền vào nó" khi tạo phương thức sao cho nó khớp với chữ ký cần thiết. Các biểu thức lambda không cho phép bạn bỏ qua danh sách tham số - một danh sách trống đưa vào một phương thức không có tham số - và do đó gây ra lỗi biên dịch. – tvanfosson

+0

@JonSkeet mã sau đây biên dịch và thực hiện thành công ngay cả khi sử dụng định nghĩa đại biểu thay cho hành động - 'public delegate void MyFun (int i); void tĩnh riêng TestJonsArgument() { MyFun fun1 = delegate {Console.WriteLine ("Ví dụ không có tham số:" + 2); }; fun1.Invoke (20); } ' – RBT

2

Cú pháp() => ... chỉ định rõ ràng rằng lambda không có tham số. Có lẽ ngôn ngữ có thể được sửa đổi để() => thực sự có nghĩa là "Suy ra các tham số của lambda này cho tôi" theo cùng cách mà cú pháp đại biểu thực hiện, nhưng điều đó sẽ làm cho ngôn ngữ phức tạp hơn. Khi thiết kế các tính năng ngôn ngữ mới, you start at minus 100 và tôi không nghĩ rằng tính năng này vượt qua bài kiểm tra. Có thể cũng có nhiều lý do kỹ thuật tại sao điều này sẽ khó thực hiện (có thể là phù hợp hơn với những gì bạn đang yêu cầu, nhưng tôi nghi ngờ các lý do kỹ thuật đã đưa ra quyết định này nếu nó được đưa ra).

0

Tôi muốn nói rằng nó buộc phải sử dụng các thông số của biểu thức lambda.

Lấy ví dụ đầu tiên của bạn, cách bạn tương tác với giá trị được truyền vào, không có đại diện cục bộ của nó.

8

Để xây dựng câu trả lời của tvanfosson; hành vi này được mô tả bằng ngôn ngữ C# 3.0 đặc điểm kỹ thuật (§7.14):

Hành vi của lambda-biểu và anonymous-phương pháp biểu thức là cùng trừ những điểm sau đây:

• nặc danh -method-expressions cho phép danh sách tham số được bỏ qua hoàn toàn, cho phép chuyển đổi thành các loại đại biểu của bất kỳ danh sách giá trị thông số nào.

• lambda-biểu thức cho phép tham số loại để được bỏ qua và suy ra trong khi anonymous-phương pháp biểu thức yêu cầu các loại tham số là quy định rõ ràng.

• Phần nội dung của một lambda-biểu thức có thể là một biểu thức hoặc một khối tuyên bố trong khi cơ thể của một anonymous-phương pháp thể hiện phải có một khối tuyên bố.

• Vì chỉ có lambda-biểu thức có thể có một cơ quan ngôn luận, không có anonymous-phương pháp biểu hiện có thể chuyển đổi thành công một loại cây biểu thức (§4.6).

Tôi nghĩ:

Action<int> action =() => Console.WriteLine("lambda"); 

là tương đương với:

Action<int> action = delegate() { Console.WriteLine("delegate"); }; 

đó sẽ không biên dịch một trong hai. Như Daniel Plaisted nói() rõ ràng nói rằng không có bất kỳ tham số nào.

Nếu có một tương đương với đại biểu {} nó có thể là:

Action<int> action = => Console.WriteLine("lambda") 

Đó là không phải là rất xinh đẹp và tôi nghi ngờ nó nghi ngờ không phải là theo tinh thần của biểu thức lambda.

5

Như những người khác đã nói, không, bạn không thể bỏ qua việc khai báo các tham số cho lambda. Nhưng, để làm sạch, tôi đề nghị cho họ một cái tên như _. Ví dụ:

Bạn không bỏ qua chúng, nhưng bạn cho biết bạn không quan tâm chúng là gì và sẽ không sử dụng chúng.

+2

và sẽ làm xáo trộn địa ngục của bất kỳ ai mới đến lambdas, hoặc không quen thuộc với quy ước của bạn. – xyz

+4

Bất cứ ai mới đến lambdas cần được đào tạo trước khi họ có thể làm việc trên bất kỳ dự án nào của chúng tôi. Đó là vấn đề tuyển dụng/đào tạo/nhân sự. Tôi thấy không có lợi ích bằng văn bản cho những người sẽ bị lẫn lộn bởi những thứ đơn giản :). – MichaelGG

+1

Tôi đề nghị dummy1', 'dummy2', vv sẽ là tên tốt hơn, vì các tên như' _' đôi khi được sử dụng cho những thứ có ý nghĩa (ví dụ '_ = someComplocatedExpression; _.Prop1 = (_.Prop2 + _.Prop3) * (_.Prop4 + _.Prop5) '[nhưng với biểu thức thứ hai thậm chí còn phức tạp hơn]. Tên' _' khá rõ ràng đề cập đến thứ mà tham chiếu của nó được lấy ở dòng trên, tên của các thuộc tính là apt để được nhiều hơn nữa thú vị để bất cứ ai đọc mã hơn sẽ là tên cho biến tạm thời – supercat

0

Điều này thì sao?

Func<int> lamdapointer =() => TwoArgMethodThatReturnsInt(10,20); // the same method cannot be called with the delegate "NoArgmethodThatReturnsInt" 


lamdapointer(); 

Delegate int NoArgmethodThatReturnsInt(); 
NoArgmethodThatReturnsInt del = NoArgmethodThatReturnsInt; // only this is possible with delegates 


public int TwoArgMethodThatReturnsInt(int x,int y) 
{ 
return x + y; 
} 

public int NoArgmethodThatReturnsInt() 
{ 
return 20; 
} 
0

Thực tế, đại biểu {} không chỉ định bất kỳ thông số nào và phù hợp với bất kỳ chữ ký phương thức đại biểu nào - vì vậy nó được phép trong lần xây dựng đầu tiên của bạn.

Biểu thức Lambda() => ...; cụ thể là các đại biểu không tham số, mâu thuẫn với chữ ký được yêu cầu bởi Action - một delegate với tham số đơn.

Bạn có thể muốn sử dụng một trong các tùy chọn sau.

Nếu bạn cần hành động để có tham số, bạn có thể thực hiện theo cách tiếp theo ("_" là ký tự pháp lý cho tên số nhận dạng).

Action<int> action = _ => Console.WriteLine("lambda");

Hoặc bạn có thể muốn sử dụng parameterless hành động như sau:

Action action =() => Console.WriteLine("lambda");

Các vấn đề liên quan