简体   繁体   English

Java或C#中的事件/代理

[英]Events/Delegates In Java or C#

I've been trying to learn about events/delegates, but am confused about the relationship between the two. 我一直在努力了解事件/代表,但我对两者之间的关系感到困惑。 I know that delegates allow you to invoke different functions without needing to know what particular function is being invoked. 我知道委托允许您调用不同的函数,而无需知道调用的是什么特定函数。 (eg: a graphing function needs to accept inputs that are different functions to be graphed). (例如:图形函数需要接受要绘制的不同函数的输入)。

But I don't see how delegates are used in Events. 但我没有看到代表如何在事件中使用。

Can someone construct a simple example (in pseudocode or C# or Java) that illustrates the workings of Delegates as related to Events? 有人可以构建一个简单的示例(伪代码或C#或Java),说明代理与事件相关的工作方式吗?

Thanks! 谢谢!

(This is all from a C# perspective.) (这完全来自C#的观点。)

I have an article about the differences between events and delegates . 我有一篇关于事件和代表之间差异文章 That covers everything mentioned below in a lot more detail. 这更详细地涵盖了下面提到的所有内容。

Basically I like to think of an event as being like a property - it's a pair of methods, that's all. 基本上我喜欢将事件看作是一个属性 - 它是一对方法,就是这样。 Instead of get/set, an event has add/remove - meaning "add this event handler" and "remove this event handler". 而不是获取/设置,事件已添加/删除 - 意味着“添加此事件处理程序”和“删除此事件处理程序”。 At the core, that's all an event is. 总的来说,这就是一个事件。

C# also has field-like events which are a shortcut: C#也有类似字段的事件 ,这是一个快捷方式:

 public event EventHandler Foo;

declares both a field and an event, with a nearly trivial add/remove implementation. 声明一个字段一个事件,具有几乎无关紧要的添加/删除实现。 Within the class, referring to Foo refers to the field. 在课堂上,指Foo指的是该领域。 Outside the class, referring to Foo refers to the event. 在课外,指Foo指的是事件。

The basic idea is that an event allows other code to subscribe to and unsubscribe from it, by passing in a delegate (the event handler ). 基本思想是,通过传入委托(事件处理程序 ),事件允许其他代码订阅和取消订阅。 Usually, subscription is implemented by creating a new multicast delegate containing the previous list of event handlers and the new one. 通常,通过创建包含先前事件处理程序列表和新事件处理程序列表的新多播委托来实现订阅。 So if you're storing the event handlers in a field called myEventHandlers , the subscription implementation might be: 因此,如果您将事件处理程序存储在名为myEventHandlers的字段中,则订阅实现可能是:

myEventHandlers += value;

Similarly unsubscription usually involves creating a new multicast delegate without the specified handler: 类似地,取消订阅通常涉及在没有指定处理程序的情况下创建新的多播委托:

myEventHandlers -= value;

Then when you want to raise/fire the event, you just call that multicast delegate - usually with a nullity check to avoid an exception being thrown if no-one has subscribed: 然后,当您想要引发/触发事件时,您只需调用该多播委托 - 通常使用无效检查,以避免在没有订阅的情况下抛出异常:

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

Using events, the subscribers don't know about each other, and can't raise the event themselves (usually). 使用事件,订阅者彼此不了解,并且不能自己(通常)提出事件。 In other words, it's a pattern of encapsulation, which has been given status within both the language and the platform. 换句话说,它是一种封装模式,已在语言和平台中获得状态。

You'll need to be specific as to which language you want. 您需要具体说明您想要的语言。 As far as I know, Java doesn't have a concept of delegates (though I could be completely wrong); 据我所知,Java没有委托的概念(尽管我可能完全错了); it tends to follow an observer pattern for event handling. 它往往遵循观察者模式进行事件处理。

C#, however, does. 但是,C#确实如此。 An event in C# has the same relation to a delegate as a property has to its backing field. C#中的event与委托具有相同的关系,因为属性具有其后备字段。 The delegate itself is what stores the pointer to the function that handles the event (or, more accurately, the list of pointers attached to the event; I use the term "pointer" loosely here). 委托本身就是存储指向处理事件的函数的指针(或者更确切地说,是附加到事件的指针列表;我在这里松散地使用术语“指针”)。

If I declare this in C#: 如果我在C#中声明:

public event EventHandler MyEvent;

And call the event like this: 并像这样调用事件:

MyEvent(this, EventArgs.Empty);

It's really just some shorthand for a full event implementation: 它实际上只是完整事件实现的一些简写:

private EventHandler myEventHandler;

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

And calling it... 并称之为......

myEventHandler(this, EventArgs.Empty);

All this is to say that an actual event exposes two operations: add and remove that are used by the consuming code to attach their event handlers to the event. 所有这一切都是说实际event暴露了两个操作: addremove消费代码使用它们将事件处理程序附加到事件。 In the default (shorthand) notation, the compiler creates a private instance member of the delegate type and uses it in the way that I described above. 在默认(简写)表示法中,编译器创建委托类型的私有实例成员,并以我上面描述的方式使用它。 When you "invoke" the event, the compiler actually substitutes the name of the event for the name of the private backing delegate it created. 当您“调用”事件时,编译器实际上会将事件名称替换为它创建的私有后代委托的名称。 This is why you can't invoke an event from a subclass--if the event is created in shorthand, then the backing member is private . 这就是您无法从子类调用event的原因 - 如果事件是以简写形式创建的,则后备成员是private

Difference is simple. 差异很简单。

delegate is a class with two fields - object and MethodInfo. delegate是一个包含两个字段的类 - object和MethodInfo。

event is a private field of type delegate and two public methods add and remove . event是类型delegate的私有字段, addremove两个公共方法。

Usually under the hood of event MulticastDelegate is used - it's a class inherited from Delegate and containing list of Delegates. 通常在事件的引擎下使用MulticastDelegate - 它是一个继承自Delegate并包含Delegates列表的类。 This allows event to have multiple subscribers. 这允许事件具有多个订户。

You can look at: http://msdn.microsoft.com/en-us/library/17sde2xt.aspx 您可以查看: http//msdn.microsoft.com/en-us/library/17sde2xt.aspx

The example is continued here: http://msdn.microsoft.com/en-us/library/xwbwks95.aspx 这个例子在这里继续: http//msdn.microsoft.com/en-us/library/xwbwks95.aspx

Basically, as was mentioned, events are just special cases of delegates, but with the changes in .NET 3.5 you can write events without using delegates, though under the hood delegates are still written. 基本上,正如前面提到的,事件只是代理的特殊情况,但是随着.NET 3.5的更改,您可以在不使用委托的情况下编写事件,尽管在代理中仍然会编写代理。

If you look at this article, they show how to use lambda expressions and anonymous functions for events: http://msdn.microsoft.com/en-us/library/ms366768.aspx 如果你看看这篇文章,他们将展示如何使用lambda表达式和匿名函数来实现事件: http//msdn.microsoft.com/en-us/library/ms366768.aspx

.Net events are just delegates under the hood: They provide some syntactic sugar in the compiler. .Net事件只是代言人:它们在编译器中提供了一些语法糖。

You can set/reset a delegate, but you can only add or remove an event handler. 您可以设置/重置委托,但只能添加或删除事件处理程序。 The rationale is that you won't care who else subscribes to an event whereas plain delegates are more used in a "callback" scenario. 理由是您不会关心其他人订阅事件,而普通代表更多地用于“回调”场景。

But at the end of all things they are very very similar. 但在所有事情的最后,他们非常相似。

Some resources: 一些资源:

C# events vs. delegates C#活动与代表

Delegates & Events - A short Q&A 代表和活动 - 简短的问答

I'm new to the java world but I have to admit I'm pretty delighted, but I still miss some C # stuff, so design this pattern that has given me good results, Java experts see some drawback in using this pattern? 我是java世界的新手,但我不得不承认我非常高兴,但我仍然想念一些C#的东西,所以设计这个模式给了我很好的结果,Java专家看到使用这个模式的一些缺点? It only supports java 8: 它只支持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");
    }
}

Feel free to ask, corrections, suggestions =) Best regards! 随意问,更正,建议=)最好的问候!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM