2009-10-15 11 views
6

Próbowałem dowiedzieć się o zdarzeniach/delegatach, ale jestem zdezorientowany co do relacji między nimi. Wiem, że delegaci umożliwiają wywoływanie różnych funkcji bez konieczności sprawdzania, która konkretna funkcja jest wywoływana. (np .: funkcja wykresu musi akceptować wejścia, które są różnymi funkcjami do wykreślenia).Wydarzenia/Delegaci W Javie lub C#

Ale nie widzę, w jaki sposób delegaci są wykorzystywani w Zdarzeniach.

Czy ktoś może skonstruować prosty przykład (w pseudokodach lub C# lub Java), który ilustruje działanie Delegatów jako powiązane ze Zdarzeniami?

Dzięki!

Odpowiedz

8

(to wszystko z perspektywy C#).

Mam article about the differences between events and delegates. Obejmuje to wszystko, o czym wspomniano poniżej, o wiele bardziej szczegółowo.

Zasadniczo lubię myśleć o wydarzeniu jako o własności - to para metod, to wszystko. Zamiast get/set, zdarzenie dodało/usunęło - co oznacza "dodaj ten moduł obsługi zdarzeń" i "usuń ten moduł obsługi zdarzeń". Najważniejsze jest to wydarzenie.

C# ma również pola jak wydarzenia będące skrót:

public event EventHandler Foo; 

deklaruje zarówno pole i zdarzenie, o prawie trywialny dodaj/usuń realizację. W klasie odwołanie do Foo odnosi się do pola. Poza zajęciami, odwołanie do Foo odnosi się do zdarzenia.

Podstawową ideą jest to, że zdarzenie pozwala innemu kodowi subskrybować i wypisać się z niego, przekazując uczestnika (zdarzenie handler). Zazwyczaj subskrypcja jest implementowana przez utworzenie nowego uczestnika multiemisji zawierającego listę poprzedniej listy programów obsługi zdarzeń i nowej.Więc jeśli przechowywania obsługi zdarzeń w polu o nazwie myEventHandlers, realizacja subskrypcja może być:

myEventHandlers += value; 

Podobnie wypisania zwykle polega na utworzeniu nowego delegata multicast bez określony Handler:

myEventHandlers -= value; 

Następnie, gdy chcesz podnieść/wystrzelić zdarzenie, po prostu zadzwoń do tego delegata multiemisji - zwykle z kontrolą nieważności, aby uniknąć zgłaszania wyjątku, jeśli nikt nie subskrybował:

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

Korzystając z wydarzeń, subskrybenci nie wiedzą o sobie nawzajem i nie mogą samodzielnie podnieść zdarzenia (zwykle). Innymi słowy, jest to wzór enkapsulacji, który otrzymał status zarówno w języku, jak i na platformie.

0

. Zdarzenia .Net to tylko delegaci pod maską: Zapewniają one trochę cukru syntaktycznego w kompilatorze.

Możesz ustawić/zresetować delegata, ale możesz tylko dodawać lub usuwać procedurę obsługi zdarzeń. Uzasadnieniem jest to, że nie dbasz o to, kto inny subskrybuje wydarzenie, podczas gdy zwykli delegaci są bardziej wykorzystywani w scenariuszu typu "oddzwanianie".

Ale pod koniec wszystkich rzeczy są bardzo podobne.

Niektóre zasoby:

C# events vs. delegates

Delegates & Events - A short Q&A

+1

Nie, wydarzenia * nie są * delegatami. Zdarzenia to zasadniczo metody dodawania/usuwania. Mówienie, że wydarzenia są delegatami, jest jak powiedzenie, że właściwości są polami. –

+0

Właściwości IMHO MUSZĄ zachowywać się jak pola, dokładnie tak jak wydarzenia będą zachowywać się jak delegaci multicast. W przeciwnym wypadku jest to mylące dla użytkownika klasy, ponieważ dostęp do właściwości i pola wygląda podobnie w źródle, jak wysyłanie zdarzeń i wysyłanie delegatów. Nie oznacza to, że właściwość lub zdarzenie musi korzystać z domyślnej implementacji (pole zaplecza, delegowanie multiemisji zastępczej). Oznacza to po prostu "właściwość/pole: Uzyskaj/ustaw wartość bez efektów ubocznych" i "wydarzenie/deleguj: uruchom wywołanie zwrotne". Dzięki właściwościom/zdarzeniom, język daje wiele sznurów, których możesz użyć rozsądnie lub powiesić się. – froh42

2

musisz być konkretne, co do których język. O ile mi wiadomo, Java nie ma pojęcia delegatów (choć mógłbym się mylić całkowicie); ma tendencję do podążania za wzorem obserwatora do obsługi zdarzeń.

C# jednak działa. event w C# ma taki sam stosunek do delegata, jak właściwość ma do swojego pola wsparcia. Sama delegata przechowuje wskaźnik do funkcji, która obsługuje wydarzenie (lub dokładniej, listę wskaźników dołączonych do zdarzenia, tutaj używam tu luźno pojęcia "wskaźnik").

Jeśli Oświadczam to w C#:

public event EventHandler MyEvent; 

i wywołać zdarzenie tak:

MyEvent(this, EventArgs.Empty); 

To naprawdę tylko niektóre skrótem pełnego wdrożenia zdarzeń:

private EventHandler myEventHandler; 

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

I nazywając to ...

myEventHandler(this, EventArgs.Empty); 

Wszystko to mówi, że rzeczywiste event udostępnia dwie operacje: add i remove, które są używane przez kod pobierający do dołączenia ich procedur obsługi zdarzeń do zdarzenia. W notacji domyślnej (skróconej) kompilator tworzy prywatny element typu delegata i używa go w sposób opisany powyżej. Kiedy "wywołasz" zdarzenie, kompilator faktycznie zastępuje nazwę zdarzenia dla nazwy utworzonego przez niego delegowanego prywatnego podkładu. Z tego powodu nie można wywoływać podklasy event - jeśli zdarzenie jest tworzone w formie skróconej, wówczas elementem wspierającym jest private.

+0

Java nie ma delegatów, ale implementujesz interfejs, a następnie subskrybujesz wydarzenie: http://java.sun.com/docs/books/tutorial/uiswing/events/intro.html –

1

Możesz zajrzeć na: http://msdn.microsoft.com/en-us/library/17sde2xt.aspx

przykładu jest kontynuowany tutaj: http://msdn.microsoft.com/en-us/library/xwbwks95.aspx

Zasadniczo, jak wspomniano, zdarzenia są tylko szczególnymi przypadkami delegatów, ale ze zmianami w .NET 3.5 Użytkownik Potrafi pisać wydarzenia bez korzystania z delegatów, choć pod maską delegaci wciąż są pisani.

Jeśli spojrzeć na ten artykuł, pokazują jak używać wyrażeń lambda i funkcji anonimowych imprez: http://msdn.microsoft.com/en-us/library/ms366768.aspx

2

Różnica jest prosta.

delegate to klasa z dwoma polami - object i MethodInfo.

event to prywatne pole typu delegate i dwie publiczne metody add i remove.

Zazwyczaj pod maską zdarzenia znajduje się MulticastDelegate - jest to klasa odziedziczona po Delegate i zawierająca listę Delegatów. Dzięki temu wydarzenie może mieć wielu subskrybentów.

+1

Wydarzenie * może * używać pole prywatne, ale nie musi mieć więcej niż własność. Konceptualnie wydarzenie to tylko dodawanie/usuwanie. –

0

Jestem nowicjuszem w świecie java, ale muszę przyznać, że jestem bardzo zachwycony, ale wciąż brakuje mi czegoś w stylu C#, więc zaprojektuj ten wzór, który dał mi dobre wyniki, eksperci Javy dostrzegają pewne wady w użyciu ten wzór? To tylko obsługuje 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"); 
    } 
} 

Zapraszam do zadawania, poprawki, sugestie =) Pozdrawiamy!