C#:理解事件语法

时间:2010-08-23 13:58:22

标签: c#

我需要一些帮助,了解如何创建新的自定义事件。我从here ...

读到
public delegate void ChangingHandler (object sender, CarArgs ca); 
public event ChangingHandler Change; 
...
private void car_Change(object sender, CarArgs ca) {
    MessageBox.Show(ca.Message());
} 
...
car.Change+=new Car.ChangingHandler(car_Change); // add event handler
...
Change(this,ca); // call event

1,我真的没有得到代表的一部分。在正常的变量声明中,

protected string str1;

但是我有额外的(ChangingHandler)。我怎么理解这个?我知道像ChangingHandler这样的东西会被用来处理这个事件,但它会让我失望。

public event ChangingHandler Change

然后

car.Change+=new Car.ChangingHandler(car_Change)

我真的没有语法new Car.ChangingHandler(car_Change)

5 个答案:

答案 0 :(得分:17)

C#中的事件有点像方法指针的集合。它说“嘿大家,如果你关心我,给我一个指向我可以调用的方法的指针,我会坚持下去,当我想向世界宣布什么是什么时,我会调用所有的方法你给了我。“

这样,有人可以给事件指向他们的方法,这被称为“事件处理程序”。只要事件的所有者认为合适,事件就会调用此方法。

从这个意义上说,代表只不过是说这个事件会接受什么样的方法。你不能让一个人给这个事件一个不带参数的方法,一个拿5个的方法,它不知道如何调用它们。因此委托是事件和事件处理程序之间的契约,告诉他们对方法签名的期望。

在您的情况下,最好只使用EventHandler<T>,它是您的事件委托的void EventHandler<T>(object sender, T eventArgs)形式的内置委托,如下所示:

public event EventHandler<CarArgs> Change;

C#实际上没有原始意义上的函数指针。代表们处理这个问题。它们就像强类型,面向对象的函数指针。当你打电话

car.Change+=new Car.ChangingHandler(car_Change);

您正在为事件提供一个新的委托(函数指针),该委托指向您的car_Change事件处理程序,告诉事件在准备好时调用您的car_Change方法。委托(new ChangeHandler(...)只是将指针包装到car_Change方法。

答案 1 :(得分:11)

事件具有特定签名。此签名定义了侦听器在哪些参数和应该具有的返回类型方面必须具有的外观。通过定义委托来表达此合同。从您的代码示例:

public delegate void ChangingHandler (object sender, CarArgs ca);

在这里,我们为以objectCarArgs为参数,并使用void返回类型的方法定义了一个委托。

接下来我们将事件声明为:

public event ChangingHandler Change;

因此,我们有一个名为Change的事件,该事件的侦听器必须与ChangingHandler委托具有相同的签名。

然后我们需要一个监听器方法:

private void car_Change(object sender, CarArgs ca) {
    MessageBox.Show(ca.Message());
} 

在这里,我们可以看到它与ChangingHandler委托具有相同的签名。

最后,我们可以将列表器附加到事件中:

car.Change+=new Car.ChangingHandler(car_Change)

因此,我们创建了一个引用ChangingHandler方法的新car_Change实例,并将委托实例传递给事件。

所有这一切,我建议使用预定义的EventHandler<T>委托,而不是创建自己的委托:

public event EventHandler<CarArgs> Change;

答案 2 :(得分:3)

另外,事实证明你不需要car.Change += new Car.ChangingHandler( car_Change );语法,因为它并不像你指出的那样直观。

您可以简单地编写car.Change += car_Change;,假设car_Change具有正确的方法签名。

答案 3 :(得分:1)

事件基于委托的概念,委托基本上是方法签名定义。就这样。就像在界面中一样,如何定义方法签名,但是没有实现它们,就可以在继承该接口的所有类中执行此操作。

委托是方法签名的定义,您可以为其定义多个方法主体,例如,给定此委托(方法签名定义):

public delegate void ChangingHandler (object sender, CarArgs ca);

您可以使用此委托(方法签名定义)定义主体:

public void SomeMethodWhichCreatesADelegateBody()
{
    ChangingHandler myChangingHandler = new ChangingHandler(
        delegate(object sender, EventArgs e) { /* the method body for myChangingHandler */ }
    );
}

这是一种定义委托的旧方式,现在使用lambdas而不是delegate关键字来创建方法体,就像我一样,但这对于这个问题并不重要。

现在事件可以被想象为一个委托(方法签名定义),其中一个body的数组被称为订阅事件,订阅一个方法体到一个事件的语法是+=并且有还有用于从事件订阅中删除方法主体的语法-=

所以这里的代码定义了ChangingHandler委托的一个正文数组(方法签名定义):

public event ChangingHandler Change;

您可以通过调用方法来订阅body(将它们添加到数组中)到此分组:

public void SomeMethodWhichSubscribesADelegateBodyToAnEvent()
{
    ChangingHandler myChangingHandler = new ChangingHandler(
        delegate(object sender, EventArgs e) { /* the method body for myChangingHandler */ }
    );

    Change += myChangingHandler;
}

现在事件的全部原因是有一个方法体的数组,你可以根据需要定义和添加,这样每当事件发生在拥有事件的对象内部时,该对象就可以执行所有那些方法在事件发生时做你想做的事。拥有该对象的对象是这样的:

if (Change != null) // You wouldn't access an array without making sure it wasn't null, would you?
{
    Change(this, new CarArgs()); // This executes every method body in it's array using the signature definition the delegate defined.
    // The delegate simply exists so this code knows the method signature
    // so it can know how to call those method body's for you.
}

答案 4 :(得分:0)

一种粗略的思考方式:委托类型定义了将成为事件基础的“函数形状”。所以ChangingHandler就是函数的样子。

更进一步,委托实例就像一个函数指针。用这些术语来思考它。

public event ChangingHandler Change定义了一个名为Change的函数指针,它将指向形状ChangingHandler的函数。

但是目前,这个函数指针没有任何指针。这就是car.Change += new Car.ChangingHandler(car_Change)位的来源。

分两步完成。代表不是正常的函数指针;它们实际上更像是函数指针堆栈,您可以将多个函数添加到委托中。这就是为什么你听到人们更常谈论“订阅”一个事件;将您的函数添加到事件将意味着它将在事件触发时被调用。使用+ =运算符将函数添加到委托“stack”。

您不能直接向委托添加函数,它必须以委托本身的形式表达。这是以一次性方式完成的,在您向事件添加函数的同一行上创建new对象;虽然从C#2.0开始,我相信你可以直接添加函数而无需调用new语法。