2009-10-15 4 views
6

Я пытался узнать о событиях/делегатах, но я смущен насчет взаимосвязи между ними. Я знаю, что делегаты позволяют вам вызывать разные функции, не требуя знать, какую именно функцию вызывается. (например: функция графического отображения должна принимать входы, которые представляют собой различные функции, которые нужно графитизировать).События/делегаты на Java или C#

Но я не вижу, как делегаты используются в Events.

Может ли кто-нибудь построить простой пример (в псевдокоде или C# или Java), который иллюстрирует работу делегатов, связанных с событиями?

Спасибо!

ответ

8

(Это все из С # точки зрения.)

У меня есть article about the differences between events and delegates. Это охватывает все, о чем упоминалось ниже, более подробно.

В принципе, мне нравится думать о том, что событие похоже на свойство - это пара методов, вот и все. Вместо get/set событие имеет add/remove, что означает «добавить обработчик событий» и «удалить этот обработчик событий». В основе всего, все это событие.

C# также имеет поле типа события которые ярлык:

public event EventHandler Foo; 

объявляет как поле и события, с почти тривиальными добавить/удалить реализацию. Внутри класса ссылка на Foo относится к полю. Вне класса, ссылаясь на Foo, это событие.

Основная идея состоит в том, что событие позволяет другому коду подписаться и отказаться от него, передав делегат (событие обработчик). Как правило, подписка реализуется путем создания нового многоадресного делегата, содержащего список обработчиков событий, а также новый обработчик событий .Так что, если вы храните обработчик событий в поле под названием myEventHandlers, реализация подписки может быть:

myEventHandlers += value; 

Аналогично отписка обычно включает в себя создание нового многоадресного делегата без указанного обработчика:

myEventHandlers -= value; 

Затем, когда вы хотите поднять/запустить событие, вы просто вызываете этот делегат многоадресной передачи - обычно с проверкой недействительности, чтобы исключить исключение, если никто не подписался:

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

Используя события, подписчики не знают друг о друге и не могут сами поднимать событие (обычно). Другими словами, это шаблон инкапсуляции, который получил статус как на языке, так и на платформе.

0

. Чистые события - это просто делегаты под капотом: они предоставляют некоторый синтаксический сахар в компиляторе.

Вы можете установить/сбросить делегат, но вы можете добавлять или удалять обработчик событий. Обоснование заключается в том, что вам все равно, кто еще подписался на событие, тогда как простые делегаты более используются в сценарии «обратного вызова».

Но в конце всех вещей они очень похожи.

Некоторые ресурсы:

C# events vs. delegates

Delegates & Events - A short Q&A

+1

Нет, события * не являются * делегатами. События - это методы добавления/удаления, в основном. Говорить о том, что события являются делегатами, - это сказать, что свойства - это поля. –

+0

Свойства IMHO ДОЛЖНЫ вести себя как поля, точно так же, как события должны вести себя как многоадресные делегаты. Иначе это вводит в заблуждение для пользователя класса, так как доступ к свойствам и полям похож на источник, как отправка события и отправка делегата. Это не означает, что для свойства или события необходимо использовать реализацию по умолчанию (поле поддержки, поддержка многоадресного делегата). Это просто означает «свойство/поле: Получить/установить значение без побочных эффектов» и «event/delegate: запустить обратный вызов». Со свойствами/событиями язык дает вам много веревки, которые вы можете использовать разумно или повеситься. – froh42

2

Вы должны быть конкретными, какой язык вы хотите. Насколько я знаю, Java не имеет понятия делегатов (хотя я мог быть совершенно неправ); он имеет тенденцию следовать шаблону наблюдателя для обработки событий.

C#, однако. Значение event в C# имеет то же отношение к делегату, что и свойство, для своего поля поддержки. Сам делегат - это то, что хранит указатель на функцию, которая обрабатывает событие (или, точнее, список указателей, прикрепленных к событию, я здесь свободно использую термин «указатель»).

Если я объявляю в C#:

public event EventHandler MyEvent; 

И называют это событие так:

MyEvent(this, EventArgs.Empty); 

Это действительно только некоторые стенография для полной реализации мероприятия:

private EventHandler myEventHandler; 

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

И называя это ...

myEventHandler(this, EventArgs.Empty); 

Все это означает, что фактический event выставляет две операций: add и remove, которые используются потребляющим кодом, чтобы прикрепить их обработчик событий к событию. В стандартном (сокращенном) обозначении компилятор создает частный экземпляр класса делегата и использует его так, как я описал выше. Когда вы «вызываете» событие, компилятор фактически заменяет имя события для имени созданного им частного делегата поддержки. Вот почему вы не можете вызывать event из подкласса - если событие создается в сокращенном виде, то элемент поддержки - private.

+0

Java не имеет делегатов, но вы реализуете интерфейс, а затем просто подписываетесь на событие: http://java.sun.com/docs/books/tutorial/uiswing/events/intro.html –

1

Вы можете посмотреть по адресу: http://msdn.microsoft.com/en-us/library/17sde2xt.aspx

На примере продолжается здесь: http://msdn.microsoft.com/en-us/library/xwbwks95.aspx

В принципе, как уже упоминалось, события лишь особые случаи делегатов, но с изменениями в .NET 3.5 Вы могут писать события без использования делегатов, хотя под капотом делегаты все еще написаны.

Если вы посмотрите на эту статью, они показывают, как использовать лямбда-выражения и анонимные функции для событий: http://msdn.microsoft.com/en-us/library/ms366768.aspx

2

Разница проста.

delegate - это класс с двумя полями - объектом и MethodInfo.

event является частным полем типа delegate и двумя общественными методами add и remove.

Обычно под капотом события MulticastDelegate используется - это класс, унаследованный от Delegate и содержащий список делегатов. Это позволяет иметь несколько подписчиков.

+1

Событие * может * использовать частное поле, но не имеет никакого отношения к собственности. Концептуально событие - это просто добавление/удаление. –

0

Я новичок в мире java, но я должен признать, что я очень рад, но я все еще скучаю по некоторым материалам C#, поэтому создайте этот шаблон, который дал мне хорошие результаты, эксперты Java видят некоторый недостаток в использовании этот шаблон? Он поддерживает только 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"); 
    } 
} 

Не стесняйтесь, исправления, предложения =) С наилучшими пожеланиями!

Смежные вопросы