2011-02-07 35 views
10

Tôi đang tìm một giải thích tốt về lý do tại sao một đoạn mã không biên dịch được và các biên dịch khác cũng tốt.Tại sao dấu ngoặc đơn xung quanh lỗi cú pháp gây ra lỗi lambda?

Thất bại:

richTextBox1.Invoke(new MethodInvoker((() => { richTextBox1.AppendText("test"); }))); 

Cung cấp cho các lỗi

tên Phương pháp dự kiến ​​

trên ngoặc mở ngay sau khi MethodInvoker(. Rõ ràng, tôi không thể quấn câu lệnh lambda của tôi trong dấu ngoặc đơn.

biên dịch:

richTextBox1.Invoke(new MethodInvoker(() => { richTextBox1.AppendText("test"); })); 

Những câu hỏi là - tại sao?

Tôi luôn cho rằng tôi có thể bọc bất kỳ tham số phương thức nào trong dấu ngoặc đơn nếu tôi muốn nhưng rõ ràng đó không phải là trường hợp với biểu thức lambda. Tôi hiểu rằng họ có phần đặc biệt, nhưng tôi vẫn không thể thấy lý do chính đáng cho việc này. Có lẽ tôi không hiểu gì về cú pháp. Tôi thực sự muốn có nó.

Nhân tiện, điều này thể hiện trong VS2008, .NET 3.5 SP1, tôi chưa thử nghiệm trong VS2010 và .NET 4.

Trả lời

7

Nó không phải là một biểu thức lambda, đó là một biểu hiện trong ngoặc đơn có chứa một biểu thức lambda. Do đó, nút cho tham số này trong cây cú pháp trừu tượng cho lời gọi phương thức này sẽ là một biểu thức được cha hóa, và không phải là một biểu thức lambda theo yêu cầu của đặc tả. Đây là lý do tại sao.

Có những nơi khác mà trình biên dịch Microsoft C# không vi phạm đặc tả và chấp nhận biểu thức như vậy mặc dù không nên (theo đặc điểm kỹ thuật) nhưng đây không phải là một trong số chúng.

Phần có liên quan của đặc tả là §6.5.

+0

Cảm ơn, điều đó có ý nghĩa. Chỉ vì tò mò - bạn có thể vui lòng cung cấp một ví dụ về địa điểm đó không? – Dyppl

+3

@Dyppl: 'Func F() {return (() => 1); } 'là hợp pháp nhưng theo đặc tả nó không nên. – jason

+0

cảm ơn! Vâng, sau đó tôi cảm thấy tốt hơn một chút về câu hỏi của tôi. Sự mâu thuẫn như vậy sẽ gây rối với đầu của bạn cuối cùng – Dyppl

3

Do trình biên dịch mong đợi ()=>{} bên trong phương thức Invoke() và trong ví dụ đầu tiên, nó không tìm thấy. Tất cả mọi thứ trong ngoặc đơn được đánh giá đầu tiên trở về một đối tượng duy nhất, trong trường hợp đó trình biên dịch mong đợi tham chiếu đến một đại biểu.

Edited Tôi đã giải quyết vấn đề tương tự với phương pháp mở rộng này:

public delegate void EmptyHandler(); 
    public static void SafeCall(this Control control, EmptyHandler method) 
    { 
     if (control.InvokeRequired) 
     { 
      control.Invoke(method); 
     } 
     else 
     { 
      method(); 
     } 
    } 

Vì vậy, bạn có thể gọi

RichTextBox rtb = new RichRextBox(); 
... 

rtb.SafeCall(()=> rtb.AppendText("test")); 
+3

Trên thực tế, các đại biểu vô danh cũng là cú pháp đường; trình biên dịch C# không dịch cú pháp lambda thành cú pháp đại biểu ẩn danh. Nó dịch cả hai thành các hàm cụ thể (hoặc các lớp với các hàm, tùy thuộc vào các bao đóng) và các đại biểu truyền thống. –

4

Bạn bị nhầm lẫn trong tiền đề rằng bạn đã viết “tham số phương pháp”. Cấu trúc bạn đã tạo không phải là cuộc gọi phương thức, bạn đã viết một biểu thức sáng tạo ủy quyền (xem đặc tả C#, phần 7.6.10.5), được cho là có một đối số duy nhất, đó phải là

  • một nhóm phương pháp,
  • một chức năng ẩn danh hoặc
  • một giá trị của một trong hai loại thời gian biên dịch động hoặc một delegate kiểu .

Trong trường hợp của bạn, nó không phải là một nhóm phương pháp (thông báo lỗi gợi ý rằng tên phương thức được mong đợi ở đó), cũng không phải là một hàm ẩn danh (vì nó là một biểu thức "ở đâu đó bên trong"), cũng không phải là giá trị của các loại đã nói.

Nếu bạn đã viết một invokation phương pháp, bạn có thể, quả thật vậy, quấn tham số trong ngoặc đơn, thậm chí nếu nó có chứa một biểu thức lambda:

void Method(Action action) 
{ 
} 
... 
Method((() => { Console.WriteLine("OK"); })); 
Các vấn đề liên quan