代表与活动之间的关系是什么?

时间:2012-02-28 17:46:08

标签: c# .net events delegates c++-cli

Delegate执行与函数指针相同的工作。它可以被视为托管世界的函数指针。它只是表示要调用的函数的地址,以及要调用其方法的特定对象。

我多次读到Delegate这个词和Event一词,但我看不出它们之间的关系。 Event是否是特定类型的代表?

5 个答案:

答案 0 :(得分:16)

简短回答:见my article on the topic。更长的答案:

事件是代表顶部的模式。它们是publisher/subscriber模式(又名observer pattern)的实现,使用委托作为表示订阅的方式。

每当你看到类似的东西时:

public event EventHandler Foo;

你应该考虑两种方法:

public void AddFooHandler(EventHandler handler) { ... }
public void RemoveFooHandler(EventHandler handler) { ... }

来自外部的客户可以做的就是订阅和取消订阅。特别是,客户端不能自己引发事件(没有为此目的提供单独的方法),也不能“替换”或删除其他订阅。

答案 1 :(得分:10)

到目前为止,答案都非常好,但他们都探索了这种关系的“机械”方面。我看一下有点不同。

想想微波炉上的“开始”按钮。该按钮为微波炉的用户提供抽象,按钮具有某些属性。它有大小,有位置,有文字,按下时有动作。

C#程序中的Button类也提供抽象,它同样具有某些属性。与微波按钮一样,它具有大小和位置以及文本和按下时的动作。

大小和位置由整数表示,文本由字符串表示。人们不会说微波炉按钮它“具有表示其大小和位置的整数以及表示其文本的字符串”。对于软件按钮,它具有大小,位置和文本的事实是按钮的语义。大小和位置以及文本由整数和字符串表示的事实是关于按钮构建的机制的事实,而不是关于目的的事实按钮或逻辑它向世界呈现的信息。

软件按钮表示被点击为活动的动作;事件说“这是一个可以点击的东西”。单击按钮时实际响应的代理集合是机制的一部分。

属性告诉您有关类的事实。它可能通过给你一个字符串来实现,但不要将字符串与属性混淆。字符串是机制,属性用于将事实传达给使用者。 事件还会告诉您有关类的事实。它使用委托来实现,因为委托是构建事件的机制

答案 2 :(得分:4)

事件本质上是代理的容器,可以触发它们。该事件还提供封装,允许事件的所有者成为触发注册代表的唯一来源。

答案 3 :(得分:3)

简短回答

通过使用委托实现事件(这就是事件看起来像委托的原因)

长答案

事件是对象发送的消息,用于指示操作的发生。该操作可能是由用户交互引起的,例如鼠标单击,或者可能由某些其他程序逻辑触发。引发事件的对象称为事件发送者。捕获事件并响应它的对象称为事件接收器。

在事件通信中,事件发送方类不知道哪个对象或方法将接收(处理)它引发的事件。所需要的是源和接收器之间的中间(或类指针机制)。 .NET Framework定义了一个特殊类型(Delegate),它提供了函数指针的功能。

委托是一个可以保存对方法的引用的类。与其他类不同,委托类具有签名,并且它只能保存对与其签名匹配的方法的引用。因此委托等同于类型安全函数指针或回调。虽然代表有其他用途,但此处的讨论主要关注代表的事件处理功能。委托声明足以定义委托类。声明提供委托的签名,公共语言运行库提供实现。以下示例显示了事件委托声明。

更多信息:

http://msdn.microsoft.com/en-us/library/17sde2xt(v=vs.100).aspx

答案 4 :(得分:3)

Delegate是一个通常包含对象引用的类,与指向方法的指针相结合,该方法是静态方法(在这种情况下,对象引用将是null)或方法保证可以处理委托中包含的对象类型。调用委托将调用指示的方法,并在适当时将包含的对象传递给它。委托也可以保存一个对象数组和一个关联方法数组,在这种情况下,调用委托将调用其相应对象上的每个方法,如果发生异常则中止该过程。所有代理,即使只有一个对象/方法对的代理,都存储为从MulticastDelegate派生的类型。

Event是由对象公开的一对方法,其他代码可以用来请求对象在某些预期的未来情况下调用特定委托,或者通知对象它不再需要调用该委托。大多数对象将接受传入的委托并将其添加到MulticastDelegate,然后在环境到达时调用该对象(调用MulticastDelegate将调用其所有成员),但对象可以自由地实现事件“add”和“删除“访问者,但他们认为合适。

一些补充说明:

  1. 事件访问器没有说明实际调用任何传入的委托的情况,也没有说明将发生的方式(例如,它是否会在任何特定线程上发生)。
  2. C#编译器和vb.net都会自动为“添加”和“删除”方法生成代码,这些方法在缺少代码的情况下使用“MulticastDelegate”。在C#中,MulticastDelegate的名称将与事件的名称相同,这可能会引起一些混淆,尤其是在较旧的C#编译器中,其中`eventName + = someDelegate`在暴露事件的类之外具有不同的含义。它会在其中。
  3. 代理是不可变的,尽管它们持有引用的对象可能不是。给定两个委托,可以生成一个新的委托,它组合了每个委托的所有对象/方法对;一个也可以生成一个委托,其中包含第一个中的所有对象/方法对,除了匹配第二个的一个,但是如果第二个委托具有多个对象/方法对,则语义相当奇怪。
  4. 如果任何组成代表或与其相当的其他代表都有可能也可以避免将通过`Delegate.Combine`生成的`MulticastDelegate`传递给事件'add'处理程序传递,因为许多事件实现使用`MulticastDelegate`加法和减法,因此遭受奇怪的“减法”语义。

由于上面的第2点,经常使用术语“事件”,尤其是在C#中,以引用与事件关联的自动生成的委托字段。但实际上,“事件”不是委托 - 它只是一对添加和删除方法(在VB中,“事件”也包含一种方法,仅用于类中,用于“提升” “一个事件(即调用先前已传递给”add“方法的委托);这只是语法糖,允许使用语法RaiseEvent EventName(params)作为直接调用适当方法的替代方法。 / p>