我理解事件的目的,特别是在创建用户界面的上下文中。我认为这是创建事件的原型:

public void EventName(object sender, EventArgs e);

事件处理程序做什么,为什么需要它们,以及如何创建一个?


当前回答

//This delegate can be used to point to methods
//which return void and take a string.
public delegate void MyDelegate(string foo);

//This event can cause any method which conforms
//to MyEventHandler to be called.
public event MyDelegate MyEvent;

//Here is some code I want to be executed
//when SomethingHappened fires.
void MyEventHandler(string foo)
{
    //Do some stuff
}

//I am creating a delegate (pointer) to HandleSomethingHappened
//and adding it to SomethingHappened's list of "Event Handlers".
myObj.MyEvent += new MyDelegate (MyEventHandler);

其他回答

另一件需要知道的事情是,在某些情况下,当你需要低级别耦合时,你必须使用委托/事件!

如果您想在应用程序的多个地方使用一个组件,您需要使组件具有低级别的耦合,并且必须将特定的无关逻辑委托到组件之外!这确保了您有一个解耦的系统和更清晰的代码。

在SOLID原则中,这是“D”,(依赖倒置原则)。

也被称为“IoC”,反转控制。

你可以用事件、委托和DI(依赖注入)来创建“IoC”。

在子类中访问方法很容易。但是从子类中访问父类中的方法更加困难。你必须把父引用传递给子引用!(或使用DI接口)

委托/事件允许我们在没有引用的情况下从子对象通信到父对象!

在上面的图中,我没有使用委托/事件,并且父组件B必须有父组件a的引用来执行方法a中无关的业务逻辑(高级别耦合)。

使用这种方法,我将不得不放置所有使用组件B的组件的所有引用!:(

在上面的图中,我使用委托/事件,组件B不必知道a(低级别耦合)

您可以在应用程序的任何地方使用组件B !

我最近做了一个如何在c#中使用事件的例子,并发布在我的博客上。我用了一个简单的例子,尽量把它讲清楚。如果它可能帮助任何人,这里是:http://www.konsfik.com/using-events-in-csharp/

它包括描述和源代码(带有大量注释),主要关注事件和事件处理程序的正确使用(类似模板)。

一些要点是:

Events are like "sub - types of delegates", only more constrained (in a good way). In fact an event's declaration always includes a delegate (EventHandlers are a type of delegate). Event Handlers are specific types of delegates (you may think of them as a template), which force the user to create events which have a specific "signature". The signature is of the format: (object sender, EventArgs eventarguments). You may create your own sub-class of EventArgs, in order to include any type of information the event needs to convey. It is not necessary to use EventHandlers when using events. You may completely skip them and use your own kind of delegate in their place. One key difference between using events and delegates, is that events can only be invoked from within the class that they were declared in, even though they may be declared as public. This is a very important distinction, because it allows your events to be exposed so that they are "connected" to external methods, while at the same time they are protected from "external misuse".

只是在这里添加到现有的伟大答案-在已接受的代码的基础上构建,它使用了委托void MyEventHandler(string foo)…

因为编译器知道SomethingHappened事件的委托类型,所以:

myObj.SomethingHappened += HandleSomethingHappened;

完全等价于:

myObj.SomethingHappened += new MyEventHandler(HandleSomethingHappened);

处理程序也可以像这样用-=取消注册:

// -= removes the handler from the event's list of "listeners":
myObj.SomethingHappened -= HandleSomethingHappened;

为了完整起见,只能在拥有该事件的类中,像这样触发事件:

//Firing the event is done by simply providing the arguments to the event:
var handler = SomethingHappened; // thread-local copy of the event
if (handler != null) // the event is null if there are no listeners!
{
    handler("Hi there!");
}

处理程序的线程本地副本是必要的,以确保调用是线程安全的——否则,线程可能会在检查事件是否为空后立即注销该事件的最后一个处理程序,我们将在那里有一个“有趣的”NullReferenceException。


c# 6为这个模式引入了一个很好的简写。它使用空传播操作符。

SomethingHappened?.Invoke("Hi there!");

这实际上是一个事件处理程序的声明——一个在触发事件时被调用的方法。要创建一个事件,你可以这样写:

public class Foo
{
    public event EventHandler MyEvent;
}

然后你可以像这样订阅这个事件:

Foo foo = new Foo();
foo.MyEvent += new EventHandler(this.OnMyEvent);

OnMyEvent()的定义如下:

private void OnMyEvent(object sender, EventArgs e)
{
    MessageBox.Show("MyEvent fired!");
}

每当Foo触发MyEvent,那么你的OnMyEvent处理程序将被调用。

你不必总是使用EventArgs的实例作为第二个参数。如果你想包含额外的信息,你可以使用一个从EventArgs派生的类(根据惯例EventArgs是基类)。例如,如果你查看WinForms中的Control上定义的一些事件,或者WPF中的FrameworkElement上定义的一些事件,你可以看到将附加信息传递给事件处理程序的事件示例。

文章中有很棒的技术答案!我没有任何技术上的补充。

在语言和软件中出现新功能的主要原因之一是市场营销或公司政治!:-)这绝不能被低估!

我认为这也适用于代表和活动!我发现它们很有用,为c#语言增加了价值,但另一方面,Java语言决定不使用它们!他们认为无论你用委托解决什么问题,你都可以用语言的现有特性来解决,比如接口。

2001年左右,微软发布了。net框架和c#语言,作为Java的竞争解决方案,所以拥有Java没有的新功能是件好事。