2009-10-15 28 views
6

Tôi đã cố gắng tìm hiểu về các sự kiện/đại biểu, nhưng tôi bối rối về mối quan hệ giữa hai người. Tôi biết rằng các đại biểu cho phép bạn gọi các hàm khác nhau mà không cần biết hàm nào cụ thể đang được gọi. (ví dụ: chức năng vẽ đồ thị cần chấp nhận các yếu tố đầu vào có các chức năng khác nhau để được lập biểu đồ).Sự kiện/Đại biểu Trong Java hoặc C#

Nhưng tôi không thấy cách đại biểu được sử dụng trong Sự kiện.

Ai đó có thể xây dựng một ví dụ đơn giản (trong mã giả hoặc C# hoặc Java) minh họa hoạt động của các đại biểu có liên quan đến Sự kiện?

Cảm ơn!

Trả lời

8

(Đây là tất cả từ góc độ C#.)

Tôi có một article about the differences between events and delegates. Điều đó bao gồm mọi thứ được đề cập bên dưới chi tiết hơn rất nhiều.

Về cơ bản tôi muốn nghĩ về một sự kiện giống như một tài sản - đó là một cặp phương pháp, đó là tất cả. Thay vì nhận/đặt, sự kiện có thêm/xóa - nghĩa là "thêm trình xử lý sự kiện này" và "xóa trình xử lý sự kiện này". Ở cốt lõi, đó là tất cả sự kiện.

C# cũng có trường như các sự kiện đó là một phím tắt:

public event EventHandler Foo; 

tuyên bố cả một lĩnh vực một sự kiện, với một add gần tầm thường/xóa thực hiện. Trong lớp học, tham chiếu đến Foo là trường. Bên ngoài lớp học, tham chiếu đến Foo đề cập đến sự kiện.

Ý tưởng cơ bản là một sự kiện cho phép mã khác đăng ký và hủy đăng ký, bằng cách chuyển qua một đại biểu (sự kiện xử lý). Thông thường, đăng ký được thực hiện bằng cách tạo một đại biểu đa phương tiện mới có chứa danh sách xử lý sự kiện trước đây và trình xử lý sự kiện mới.Vì vậy, nếu bạn đang lưu trữ xử lý sự kiện trong một lĩnh vực được gọi là myEventHandlers, việc thực hiện thuê bao có thể là:

myEventHandlers += value; 

Tương tự việc hủy đăng ký thường liên quan đến việc tạo ra một đại biểu multicast mới mà không xử lý theo quy định:

myEventHandlers -= value; 

Sau đó, khi bạn muốn tăng/kích hoạt sự kiện, bạn chỉ cần gọi đại biểu multicast đó - thường là với kiểm tra vô hiệu để tránh trường hợp ngoại lệ bị ném nếu không có ai đăng ký:

EventHandler handler = myEventHandlers; 
if (handler != null) 
{ 
    // You could pass in a different "sender" and "args" of course 
    handler(this, EventArgs.Empty); 
} 

Sử dụng sự kiện, người đăng ký không biết về nhau và không thể tự nâng cao sự kiện (thường là). Nói cách khác, đó là một mô hình đóng gói, đã được đưa ra trạng thái trong cả ngôn ngữ và nền tảng.

0

. Sự kiện Net chỉ là đại biểu dưới mui xe: Chúng cung cấp một số đường cú pháp trong trình biên dịch.

Bạn có thể đặt/đặt lại đại biểu, nhưng bạn chỉ có thể thêm hoặc xóa trình xử lý sự kiện. Lý do là bạn sẽ không quan tâm ai khác đăng ký một sự kiện trong khi các đại biểu đơn giản hơn được sử dụng trong một kịch bản "gọi lại".

Nhưng vào cuối tất cả mọi thứ, chúng rất giống nhau.

Một số nguồn:

C# events vs. delegates

Delegates & Events - A short Q&A

+1

Không, sự kiện * không phải * đại biểu. Sự kiện là thêm/loại bỏ các phương pháp, về cơ bản. Nói rằng các sự kiện là đại biểu giống như nói rằng các thuộc tính là các trường. –

+0

Các thuộc tính IMHO SHALL hoạt động giống như các trường, giống như các sự kiện sẽ hoạt động như các đại biểu multicast. Khác là nó gây hiểu nhầm cho người dùng của một lớp vì quyền truy cập thuộc tính & trường trông giống như trong nguồn như gửi công việc sự kiện và công văn ủy nhiệm. Điều này không có nghĩa là tài sản hoặc sự kiện cần sử dụng triển khai mặc định (trường sao lưu, ủng hộ ủy quyền đa phương tiện). Nó chỉ có nghĩa là "thuộc tính/trường: Nhận/Đặt một giá trị không có tác dụng phụ" và "sự kiện/đại biểu: chạy một cuộc gọi lại". Với các thuộc tính/sự kiện, ngôn ngữ cung cấp cho bạn rất nhiều sợi dây mà bạn có thể sử dụng một cách hợp lý hoặc treo cổ. – froh42

2

Bạn sẽ cần phải được cụ thể như ngôn ngữ mà bạn muốn. Theo tôi biết, Java không có khái niệm về các đại biểu (mặc dù tôi có thể hoàn toàn sai); nó có xu hướng theo một mô hình quan sát để xử lý sự kiện. Tuy nhiên,

C#. An event trong C# có cùng mối quan hệ với đại biểu là thuộc tính có trường hậu thuẫn của nó. Bản thân đại biểu chính là thứ lưu trữ con trỏ tới hàm xử lý sự kiện (hoặc, chính xác hơn, danh sách các con trỏ gắn liền với sự kiện; tôi sử dụng thuật ngữ "con trỏ" ở đây).

Nếu tôi tuyên bố điều này trong C#:

public event EventHandler MyEvent; 

Và gọi sự kiện như thế này:

MyEvent(this, EventArgs.Empty); 

Nó thực sự chỉ là một số viết tắt cho việc thực hiện sự kiện đầy đủ:

private EventHandler myEventHandler; 

public event EventHandler MyEvent 
{ 
    add { myEventHandler += value; } 
    remove { myEventHandler -= value; } 
} 

Và gọi nó là ...

myEventHandler(this, EventArgs.Empty); 

Tất cả điều này là để nói rằng một thực tế event cho thấy hai hoạt động: addremove được sử dụng bởi mã tiêu thụ để đính kèm trình xử lý sự kiện của họ vào sự kiện. Trong ký hiệu mặc định (viết tắt), trình biên dịch tạo ra một cá thể cá thể thành viên của kiểu ủy nhiệm và sử dụng nó theo cách mà tôi đã mô tả ở trên. Khi bạn "gọi" sự kiện, trình biên dịch thực sự thay thế tên của sự kiện cho tên của đại biểu sao lưu riêng mà nó tạo ra. Đây là lý do tại sao bạn không thể gọi một số event từ một lớp con - nếu sự kiện được tạo theo cách viết tắt, thì thành viên sao lưu là private.

+0

Java không có đại biểu, nhưng bạn triển khai giao diện sau đó chỉ cần đăng ký sự kiện: http://java.sun.com/docs/books/tutorial/uiswing/events/intro.html –

1

Bạn có thể xem xét: http://msdn.microsoft.com/en-us/library/17sde2xt.aspx

Ví dụ được tiếp tục ở đây: http://msdn.microsoft.com/en-us/library/xwbwks95.aspx

Về cơ bản, như đã đề cập, các sự kiện chỉ là trường hợp đặc biệt của các đại biểu, nhưng với những thay đổi trong .NET 3.5 bạn có thể viết các sự kiện mà không cần sử dụng các đại biểu, mặc dù dưới các đại biểu mui xe vẫn được viết.

Nếu bạn nhìn vào bài viết này, chúng cho thấy làm thế nào để sử dụng biểu thức lambda và chức năng ẩn danh cho các sự kiện: http://msdn.microsoft.com/en-us/library/ms366768.aspx

2

khác biệt rất đơn giản.

delegate là một lớp có hai trường - đối tượng và MethodInfo.

event là trường riêng tư thuộc loại delegate và hai phương thức công khai addremove.

Thông thường dưới mui xe của sự kiện MulticastDelegate được sử dụng - đó là một lớp được kế thừa từ Delegate và chứa danh sách Đại biểu. Điều này cho phép sự kiện có nhiều người đăng ký.

+1

Sự kiện * có thể * sử dụng một trường riêng tư, nhưng không phải là bất kỳ trường nào hơn thuộc tính. Khái niệm một sự kiện chỉ là thêm/xóa. –

0

Tôi mới vào thế giới java nhưng tôi phải thừa nhận rằng tôi rất vui, nhưng tôi vẫn nhớ một số công cụ C#, vì vậy thiết kế mẫu này đã cho tôi kết quả tốt, các chuyên gia Java thấy một số nhược điểm trong việc sử dụng mô hình này? Nó chỉ hỗ trợ java 8:

@FunctionalInterface 
public interface IEvent<TEventArgs extends Object> { 
    void invoke(TEventArgs eventArgs); 
} 

public class EventHandler<TEventArgs> 
{ 
    private ArrayList<IEvent<TEventArgs>> eventDelegateArray = new ArrayList<>(); 
    public void subscribe(IEvent<TEventArgs> methodReference) 
    { 
     eventDelegateArray.add(methodReference); 
    } 
    public void unSubscribe(IEvent<TEventArgs> methodReference) 
    { 
     eventDelegateArray.remove(methodReference); 
    } 
    public void invoke(TEventArgs eventArgs) 
    { 
     if (eventDelegateArray.size()>0) 
      eventDelegateArray.forEach(p -> p.invoke(eventArgs)); 
    } 
} 

public class DummyEventProducer 
{ 
    // The event 
    public EventHandler<String> myEvent = new EventHandler<>(); 

    public void onMyEvent(String A) 
    { 
     myEvent.invoke(A); 
    } 
} 


public class DummySubscriber { 

    // The method will be subscribed to the event 
    public void methodCallWhenEventGetTriggered(String eventArgs) 
    { 
     System.out.println("event fired with eventargs: " + eventArgs); 
    } 
} 


public class Main { 

    public static void main(String[] args) 
    { 
     // A dummy producer 
     DummyEventProducer producer = new DummyEventProducer(); 

     // A dummy subscribers 
     DummySubscriber testingInstanceA = new DummySubscriber(); 
     DummySubscriber testingInstanceB = new DummySubscriber(); 
     DummySubscriber testingInstanceC = new DummySubscriber(); 

     // We create decoupled event links because we want to un-subscribe later 
     IEvent<String> EventSink1 = testingInstanceA::methodCallWhenEventGetTriggered; 
     IEvent<String> EventSink2 = testingInstanceB::methodCallWhenEventGetTriggered; 
     IEvent<String> EventSink3 = testingInstanceC::methodCallWhenEventGetTriggered; 

     // subscribe to the event on dummy producer 
     producer.myEvent.subscribe(EventSink1); 
     producer.myEvent.subscribe(EventSink2); 
     producer.myEvent.subscribe(EventSink3); 

     // fire the event on producer 
     producer.onMyEvent("Hola MUNDO with decoupled subscriptions!"); 

     // unsubscribe to the event on dummy producer 
     producer.myEvent.unSubscribe(EventSink1); 
     producer.myEvent.unSubscribe(EventSink2); 
     producer.myEvent.unSubscribe(EventSink3); 

     // fire the event on producer again 
     producer.onMyEvent("Hola MUNDO! with no events subscriptions :("); 

     // IF YOU DON CARE ABOUT UNSUBSCRIBE YOU CAN LINK EVENTS DIRECTLY TO THE SUBSCRIBER 
     producer.myEvent.subscribe(testingInstanceA::methodCallWhenEventGetTriggered); 
     producer.myEvent.subscribe(testingInstanceB::methodCallWhenEventGetTriggered); 
     producer.myEvent.subscribe(testingInstanceC::methodCallWhenEventGetTriggered); 

     // fire the event on producer again 
     producer.onMyEvent("Hola MUNDO! with strong link subscriptions (cannot be un-subscribed"); 
    } 
} 

Hãy hỏi, sửa chữa, gợi ý =) Trân trọng!

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