2010-09-19 33 views
21

Trước tiên, tôi đã đọc một số diễn đàn và trợ giúp trong MSDN và tất cả đều nói rằng một đại biểu không thể bị quá tải.C# - Làm thế nào tôi có thể "quá tải" một đại biểu?

Bây giờ, tôi muốn có một cái gì đó như thế này:

public delegate void OneDelegate(); 
public delegate void OneDelegate(params object[] a); 

public void DoNothing(params object[] a) {} 
public void DoSomething() { /* do something */ } 

private OneDelegate someFunction; 

someFunction = new OneDelegate(DoSomething); 
someFunction = new OneDelegate(DoNothing); 

Vì vậy, như bạn biết, bạn KHÔNG THỂ làm được điều này, bởi vì OneDelegate chỉ đề cập đến một trong những đầu tiên và không phải là người thứ hai. Nhưng, có cách nào để làm điều này không? hay đại loại thế?

PS1: Tôi không có bất kỳ số lượng khai báo OneDelegate nào, không chỉ một hoặc hai.
PS2: Xin lỗi vì tiếng Anh xấu của tôi.

+2

Gần nhất bạn có thể nhận được là quá tải bằng cách sử dụng generics, chính xác như tất cả các hành động quá tải <> và Func <>. (Trong đó các đối số chung đại diện cho các kiểu tham số và kiểu trả về.) Tất nhiên, một khi bạn đi xa như vậy, nó đặt ra câu hỏi tại sao không chỉ sử dụng Action <> và Func <> ngay từ đầu? –

+1

Tôi muốn chỉ có MỘT LOẠI chức năng này để tôi có thể nói "Này, ở đây bạn có một chức năng, gọi nó!". Và tôi không thể làm điều đó với Action <> AND Func <>. –

Trả lời

32

Hãy tưởng tượng trong giây lát điều này là có thể. Giả sử tôi có thể có một đại biểu quá tải:

public delegate void OneDelegate(int i); 
public delegate void OneDelegate(string s); 

Bây giờ tưởng tượng Tôi tuyên bố một biến kiểu này và sau đó gán một chức năng để nó, ví dụ:

OneDelegate myDelegate = StringMethod; 

nơi StringMethod được khai báo thusly:

public void StringMethod(string s) { Console.WriteLine(s); } 

Bây giờ bạn vượt qua myDelegate đối với một số mã khác, và mã mà thực hiện điều này:

myDelegate(47); 

Bạn mong đợi điều gì sẽ xảy ra trong trường hợp này? Làm thế nào có thể gọi thời gian chạy StringMethod() với một đối số nguyên?

Nếu bạn thực sự muốn có một đại biểu có thể mất bất kỳ tập hợp các thông số ở tất cả các, sau đó lựa chọn duy nhất là phải có một với một mảng params object[]:

public delegate void OneDelegate(params object[] parameters); 

Nhưng sau đó bạn sẽ phải gán cho nó là một chức năng mà thực sự có thể xử lý bất kỳ mảng đối tượng, ví dụ:

public void MyMethod(params object[] parameters) 
{ 
    if (parameters == null || parameters.Length == 0) 
     throw new ArgumentException("No parameters specified."); 
    if (parameters.Length > 1) 
     throw new ArgumentException("Too many parameters specified."); 

    if (parameters[0] is int) 
     IntMethod((int) parameters[0]); 
    else if (parameters[0] is string) 
     StringMethod((string) parameters[0]); 
    else 
     throw new ArgumentException("Unsupported parameter type."); 
} 

Như bạn có thể thấy, đây bị lộn xộn thật nhanh chóng. Vì vậy, tôi gửi cho bạn rằng nếu bạn cần một đại biểu như vậy, bạn có thể đã phạm sai lầm ở đâu đó trong thiết kế kiến ​​trúc của bạn. Xác định lỗ hổng này và sửa chữa thiết kế trước khi bạn tiến hành triển khai, nếu không thì khả năng bảo trì mã của bạn sẽ bị ảnh hưởng.

+1

Có lẽ "sai lầm" trong thiết kế kiến ​​trúc của anh ta là sử dụng C#, sau đó? F # (và các ngôn ngữ chức năng khác có khớp mẫu) không có vấn đề gì với hàm không có gì hoặc danh sách. – Gabe

+0

@Gabe: Đủ công bằng - nhưng hãy nhớ rằng F # là một mô hình lập trình hoàn toàn khác, có thể có hoặc không phù hợp với dự án cụ thể của mình. – Timwi

+3

Tôi không gợi ý rằng anh ấy muốn sử dụng F #. Tôi chỉ không đồng ý với quan niệm rằng chạy vào một giới hạn của C# có khả năng được gây ra bởi thiết kế kém của chương trình chứ không phải là thiết kế kém (hoặc chỉ là một thiếu sót) của C#. – Gabe

6

Lớp Action "thực hiện việc này". Đó là một đại biểu với các mẫu, vì vậy bạn có thể có một đại biểu như thế này:

public delegate void D<T>(params T[] arg); 

func() { 
    D<object> d1; 
} 

Đây có lẽ là gần như là bạn sẽ nhận được, tức là bạn cần một kiểu mẫu như một tham số.

Chỉnh sửa: Dựa trên nhận xét Tôi đoán bạn sau khi chuyển giao đại biểu cho một chức năng khác. Bạn có thể thực hiện nó bằng cách đi dọc theo các đối số là tốt. Rất tiếc, bạn không thể thực hiện việc này mà không sử dụng thông số tham số cho fire.

public void bar() { 
    D<string> d = ...; 
    fire(d, "first", "second"); 
    fire(d); // also works 
} 

public void fire<T>(D<T> f, params T[] args) { 
    f(args); 
} 
Các vấn đề liên quan