2011-04-08 50 views
7

Tôi muốn cung cấp các đối tượng trong thư viện lớp có khả năng “xuất ra” thư mà không phải lo lắng về việc nó đang được xuất ra như thế nào. Thư viện lớp có thể được sử dụng trong một ứng dụng giao diện điều khiển, một ứng dụng Windows WinForm hoặc WPF hoặc một trang web.Điều gì sẽ sử dụng? đại biểu, sự kiện hoặc Func <T>?

Tôi đã quyết định ban đầu là tôi sẽ sử dụng một đại biểu để xử lý việc này. Tôi thực hiện điều này bằng cách sử dụng các lớp học, nhưng trình biên dịch không giống như các đại biểu khi tôi đã cố gắng để đưa các đại biểu vào một giao diện mà mỗi đối tượng này vốn có.

Tôi thấy rằng tôi có thể di chuyển đại biểu ra khỏi giao diện và sau đó đã có thể biên dịch nhưng tôi không chắc rằng điều này hoàn thành những gì tôi đang cố gắng làm .. Nó cũng có vẻ như một kludge vì vậy tôi muốn hỏi nếu bất kỳ của bạn có những ý tưởng khác nhau để thực hiện điều này ...

Giao diện:

namespace Test 
{ 
    using System; 
    using System.Xml.Linq; 

    public interface IAction 
    { 
    DisplayMessageDelegate DisplayMessage(string message); 
    void Execute(); 
    XElement Serialize(XName elementName); 
    } 

    public delegate void DisplayMessageDelegate(string message); 
} 

Từ đó, tôi không chắc chắn làm thế nào để thực hiện hành vi này: (BTW, tôi biết rằng mã này sẽ không biên dịch ...)

public class ActionClass1 : IAction 
{ 
    // Other methods not shown... 
    void Execute() 
    { 
    if (this.DisplayMessage != null) 
    { 
     this.DisplayMessage(“Hello”); 
    } 
    } 
} 

public class ConsoleClass 
{ 
    ActionClass1 class1 = new ActionClass1(); 
    class1.DisplayMessage = { x => Console.WriteLine(x); }; 
} 

public class WinFormClass 
{ 
    ActionClass1 class1 = new ActionClass1(); 
    Class1.DisplayMessage = {x => DisplayTextBox.Text = x; }; 
} 

Trả lời

11

Nếu bạn muốn có khả năng kết nối nhiều đại biểu để trả lời một cuộc gọi đến Execute, tôi chắc chắn sẽ sử dụng số event. Nếu bạn chỉ muốn một hành động đơn lẻ được kết nối, hãy sử dụng số đại diện Action hoặc Func.

Ví dụ của bạn, một trong các đại biểu Action sẽ hoạt động. Trong trường hợp của bạn, nó sẽ là Action<string> kể từ khi đại biểu của bạn có một đối số chuỗi. An Action chỉ đơn giản là một đại biểu có số không hoặc nhiều đối số và trả về void. Có vẻ như bạn không trả lại bất kỳ thứ gì, vì vậy đó là lý do tôi đề xuất Action.

Bạn chỉ muốn sử dụng Func<TResult> nếu người được ủy quyền của bạn cần trả lại thứ gì đó. Sự khác biệt giữa FuncActionFunc đại biểu có loại trả lại và Action đại biểu thì không. Một trong các đại biểu này có các phiên bản chung có thể mất tối đa 16 hoặc nhiều đối số.

Nếu bạn cần hơn 16 đối số trên đại biểu, bạn có thể muốn xem xét lại thiết kế :)

+1

Cần lưu ý rằng nếu bạn cần bất kỳ điều gì phức tạp hơn so với thông số, thay đổi/thoát ... Hành động/Func sẽ không hoạt động. Ngoài ra một 'nicety' khác là bạn có thể Đặt tên các tham số một cách thích hợp (intellisense). Điều đó đang được nói tôi cũng sẽ sử dụng Action . – Jake

1

Định nghĩa giao diện của bạn sai. Bạn sẽ cần phải chỉ định nó như vậy:

namespace Test 
{ 
    using System; 
    using System.Xml.Linq; 

    public interface IAction 
    { 
    DisplayMessageDelegate DisplayMessage { get; set; }; 
    void Execute(); 
    XElement Serialize(XName elementName); 
    } 

    public delegate void DisplayMessageDelegate(string message); 
} 

và sau đó triển khai giao diện.

4

Bạn có thể thực hiện việc này bằng cách sử dụng Action<string>.

Bạn không muốn sử dụng Func<T>, vì điều này xác định đại biểu không có đối số nhưng trả về một giá trị kiểu T. Action<T>, mặt khác, là đại biểu nhận một đối số duy nhất của loại T.

tôi sẽ đề nghị cố gắng:

public interface IAction 
{ 
    Action<string> DisplayMessage { get; set; } 

    void Execute(); 
    XElement Serialize(XName elementName); 
} 

Một khi bạn thực hiện giao diện này (hoàn toàn), bạn có thể sử dụng nó thông qua:

public class ConsoleClass 
{ 
    public void SomeMethod() 
    { 
     ActionClass1 class1 = new ActionClass1(); 
     class1.DisplayMessage = x => Console.WriteLine(x); 
    } 
} 

Hoặc:

public class ConsoleClass 
{ 
    public void SomeMethod() 
    { 
     ActionClass1 class1 = new ActionClass1(); 
     class1.DisplayMessage = this.Print; 
    } 

    private void Print(string message) 
    { 
     Console.WriteLine(message); 
    } 
} 

Bạn có thể làm điều tương tự với các sự kiện, tuy nhiên, tôi sẽ đặt câu hỏi này. API của bạn mô tả hành động sẽ xảy ra, không phải sự kiện đang xảy ra mà bạn đang phản hồi - và như vậy, tôi sẽ không đề xuất sự kiện.

1

Đây

DisplayMessageDelegate DisplayMessage(string message); 

bạn mô tả phương pháp mà chấp nhận chuỗi và trả về DisplayMessageDelegate. Sử dụng

event DisplayMessageDelegate DisplayMessage; 

để thay thế.

0

Cá nhân tôi sẽ có mặc dù tốt nhất bạn nên có lớp cơ sở trừu tượng đã xác định phương thức trừu tượng có tên là DisplayMessage và sau đó mở rộng lớp cơ sở đó bằng cách lấy ra từ nó để thay đổi hành vi của cách hiển thị thông báo.

+0

Tôi đã xem xét rằng ... Tôi đã bỏ qua thực tế (trong một nỗ lực để đơn giản hóa vấn đề) rằng các lớp dẫn xuất này sẽ nằm trong bộ sưu tập Danh sách , nơi tôi sẽ thực hiện vòng lặp ForEach để thực thi phương thức Thi hành cho từng mục, cài đặt lên "DisplayMessage" dựa trên loại ứng dụng tôi đang chạy vào thời điểm đó ... –

0

Thay vì:

DisplayMessageDelegate DisplayMessage(string message); 

Đỗ:

event Action<string> DisplayMessage; 

Sau đó sử dụng DisplayMessage mỗi bình thường, các sự kiện được các đại biểu.

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