2009-06-10 35 views
33

Tôi không thể là người duy nhất cảm thấy mệt mỏi khi xác định và đặt tên một đại biểu chỉ với một cuộc gọi duy nhất đến một thứ đòi hỏi một đại biểu. Ví dụ, tôi muốn gọi .Refresh() trong một hình thức từ chủ đề có thể khác, vì vậy tôi đã viết mã này:các đại biểu vô danh trong C#

private void RefreshForm() 
{ 
    if (InvokeRequired) 
     Invoke(new InvokeDelegate(Refresh)); 
    else 
     Refresh(); 
} 

Tôi thậm chí không chắc rằng tôi đã đến, tôi chỉ đọc đủ để được sợ rằng nó sẽ không hoạt động ở giai đoạn sau.
InvokeDelegate thực sự được khai báo trong một tệp khác, nhưng tôi có thực sự cần một đại biểu toàn bộ dành riêng cho việc này không? không có bất kỳ đại biểu chung nào cả?
Ý tôi là, ví dụ, có một lớp Bút, nhưng cũng có Bút. pen-of-choice do đó bạn không phải làm lại toàn bộ nội dung. Nó không giống nhau, nhưng tôi hy vọng bạn hiểu ý tôi.

+1

Không có điều như "đại biểu ẩn danh" trong C#. Có các đại biểu (như những gì bạn đang sử dụng) và các phương thức nặc danh (chỉ có thể truy cập thông qua một đại biểu). – Lucas

+3

Tôi đoán vì thông số C# sử dụng thuật ngữ "phương thức ẩn danh" nên đó là cách chính xác. Tuy nhiên, thuật ngữ này được sử dụng bởi rất nhiều người để có nghĩa là một đại biểu được khởi tạo với một phương thức nặc danh như một tham số. Vì vậy, chúng có ý nghĩa tương tự, nhưng ngữ cảnh trong đó một người nào đó có thể sử dụng một cụm từ trên người kia phụ thuộc thường xuyên vào việc có một nhiệm vụ đại biểu hay không hoặc nếu phương thức nặc danh đang được truyền trực tiếp sang phương thức khác. Tôi hoan nghênh bất kỳ đối số nào ngược lại. –

Trả lời

52

Có. Trong .NET 3.5, bạn có thể sử dụng FuncAction đại biểu. Các đại biểu Func trả về một giá trị, trong khi các đại biểu Action trả về void. Dưới đây là tên của các loại hình như sau:

System.Func<TReturn> // (no arg, with return value) 
System.Func<T, TReturn> // (1 arg, with return value) 
System.Func<T1, T2, TReturn> // (2 arg, with return value) 
System.Func<T1, T2, T3, TReturn> // (3 arg, with return value) 
System.Func<T1, T2, T3, T4, TReturn> // (4 arg, with return value) 

System.Action // (no arg, no return value) 
System.Action<T> // (1 arg, no return value) 
System.Action<T1, T2> // (2 arg, no return value) 
System.Action<T1, T2, T3> // (3 arg, no return value) 
System.Action<T1, T2, T3, T4> // (4 arg, no return value) 

Tôi không biết tại sao chúng dừng lại ở mức 4 args, nhưng nó luôn đủ cho tôi.

+2

4 không phải là một quy tắc cụ thể, nhưng quá khứ mà bạn nên ít nhất xem xét kết hợp các tham số theo một cách nào đó. –

+1

Khi tôi đang chuyển một số mã .NET cũ hơn thành 3.5 và tôi thấy một đại biểu tôi hoán đổi chúng cho Func hoặc Action. – RichardOD

+10

Phiên bản tiếp theo của khung công tác sẽ bao gồm Func và Hành động của hơn bốn tham số. –

4

phiên bản ngắn:

Invoke((MethodInvoker)delegate { Refresh(); }); 

Sau đó, bạn cũng có thể thả các kiểm tra của InvokeRequired; bạn có thể gọi nó như nó được. cũng hoạt động nếu bạn cần phải vượt qua các thông số, vì vậy không có nhu cầu cho các đại biểu tham số cụ thể khác (chỉ hoạt động ngang ngửa với các đại biểu hành động tham số-ít cũng):

private void SetControlText(Control ctl, string text) 
{ 
    Invoke((MethodInvoker)delegate { ctl.Text = text; }); 
} 
+0

Tại sao bạn sẽ tạo một đại biểu vô danh chỉ để truyền nó cho một loại đại biểu hiện có? Bạn chỉ nên sử dụng loại ủy nhiệm trực tiếp. –

+2

@Brian: bạn có nghĩa là như thế này: Gọi (new MethodInvoker (delegate {ctl.Text = text;})); ? Theo như tôi có thể thấy rằng sản xuất chính xác cùng một mã IL như mã của tôi ở trên, vì vậy nó xuống đến sở thích cá nhân, tôi đoán. –

+0

sự khác nhau giữa MethodInvoker và Action là gì? Ngoài ra, tôi đang kiểm tra InvokeRequired vì nó có vẻ là một thực hành tốt hơn, ví dụ, nhanh hơn. – Nefzen

26

Có các đại biểu hành động bạn có thể sử dụng , như vậy:

private void RefreshForm() 
{ 
    if (InvokeRequired) Invoke(new Action(Refresh)); 
    else Refresh(); 
} 

Hoặc, với cú pháp lambda:

private void RefreshForm() 
{ 
    if (InvokeRequired) Invoke((Action)(() => Refresh())); 
    else Refresh(); 
} 

Cuối cùng có vô danh đại biểu cú pháp:

private void RefreshForm() 
{ 
    if (InvokeRequired) Invoke((Action)(delegate { Refresh(); })); 
    else Refresh(); 
} 
+2

kỳ quặc, cú pháp thứ hai và thứ ba không hoạt động nói rằng nó không thể chuyển đổi nó thành System.Delegate vì nó không phải là một loại đại biểu. Tuy nhiên, Hành động chắc chắn là điều tôi muốn. – Nefzen

+1

đại biểu ẩn danh không thể được chuyển theo cách này để Gọi vì họ không thuộc loại đại biểu. Những gì bạn viết ở đây thậm chí không biên dịch. –

+1

Heh, đó là những gì tôi nhận được không kiểm tra trước khi đăng. Tôi sẽ sửa chữa càng sớm càng tốt. –

1

Có, có các đại biểu chung. Action<T1, T2...> là một đại biểu chung mà phải mất một số tham số và trả về không có giá trị, và Func<T1, T2...R> là một đại biểu chung mà có một số tham số và trả về một giá trị.

2

Tôi có thực sự cần toàn bộ đại biểu dành riêng cho việc này không? không có bất kỳ đại biểu chung nào cả?

Xác định đại biểu của riêng bạn thực sự có thể thực hiện gỡ lỗi dễ dàng hơn, nếu chỉ vì Intellisense có thể cho bạn biết tên tham số của bạn. Ví dụ, bạn viết một đại biểu như thế này:

public delegate int UpdateDelegate(int userID, string city, string, state, string zip); 

Khi bạn sử dụng nó mã, .NET sẽ thông báo cho bạn trong những cái tên tham số, ủy tên, vv, do đó, rất nhiều bối cảnh ngay trong định nghĩa đại biểu nếu bạn không chắc chính xác một cái gì đó được sử dụng như thế nào.

Tuy nhiên, nếu bạn không nhớ hy sinh Intellisense, đã có một lớp đại biểu definined trong namespace System có thể được sử dụng như các đại biểu ad-hoc:

Func<T> 
Func<T, U> 
Func<T, U, V> 
Func<T, U, V, W> 
Action, Action<T> 
Action<T, U> 
Action<T, U, V> 
Action<T, U, V, W> 

Chỉ ActionAction tồn tại trong .NET 2.0, nhưng nó đủ dễ dàng để khai báo một lớp trợ giúp với các đại biểu còn lại mà bạn cần cho các loại hàm ad hoc linh tinh này.

8

Trong trường hợp cụ thể này, bạn có thể (và nên) chỉ cần sử dụng MethodInvoker để làm điều này ... đó là lý do tại sao nó tồn tại.

if (InvokeRequired) 
    Invoke(new MethodInvoker(Refresh)); 
else 
    Refresh(); 

Nếu bạn đang làm một cái gì đó khác mà bạn có thể, như những người khác đã trả lời sử dụng Func < T, ... > hoặc hành động < T, ... > nếu họ phù hợp với trường hợp sử dụng của bạn.

+1

Đây là giải pháp tốt nhất cho .NET 2.0 –

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