2010-08-23 48 views
6

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

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日,我真的不得到代表的一部分。在一个正常的变量declartion,

protected string str1; 

但在这里我有多余的(ChangingHandler)。我如何理解这一点?我知道像ChangingHandler这样的东西会被用来处理事件,但它会把我抛弃。

public event ChangingHandler Change 

然后

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

我真的不得到语法new Car.ChangingHandler(car_Change)

回答

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

请注意,您不需要显式创建委托实例。你可以做'car.Change + = car_Change;'(这非常习惯) – bruceboughton 2010-08-23 15:00:11

3

而且事实证明你不需要car.Change += new Car.ChangingHandler(car_Change);作为语法时才它并不像你指出的非常直观。

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

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; 
0

一个思考它的粗暴的方式:委托类型定义了将要“的功能形状”成为你的事件的基础。所以ChangingHandler是函数的样子。进一步说,委托实例就像一个函数指针。用这些术语来思考它。

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

但是目前这个函数指针没有指向任何东西。这就是car.Change += new Car.ChangingHandler(car_Change)比特进来的地方。

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

你不能直接将一个函数直接添加到委托,它已经用委托本身表达。这是以一次性方式完成的,在你将函数添加到事件的同一行上创建一个new对象;尽管自C#2.0以来我相信你可以直接添加函数而不用调用new语法。

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 */ } 
    ); 
} 

这虽然定义为代表的老风格,现在它更具可读性,而不是使用委托关键字的lambda表达式像我一样创建方法体,但这对于这些并不重要 问题。

现在可以将事件想象成一个委托(方法签名定义),其中包含一个body数组,用于订阅事件,订阅方法体的语法为+=,还有用于从事件的订阅是-=

所以这里这个代码定义身体为ChangingHandler委托阵列(方法签名的定义)去除的方法体:

public event ChangingHandler Change; 

而且你可以订阅身体的(它们添加到数组)通过calli进行分组NG的方法:

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. 
}