繁体   English   中英

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

[英]What is the relationship between delegates and events?

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

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

简答:看看我关于这个主题的文章 更长的回答:

事件是代表之上的模式。 它们是发布者/订阅者模式(也称为观察者模式 )的实现,使用委托作为表示订阅的手段。

每当你看到类似的东西:

public event EventHandler Foo;

你应该考虑两种方法:

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

来自外部的客户可以做的就是订阅和取消订阅。 尤其是,客户端无法提高(被提供用于该目的,而不需要单独的方法)的情况下本身也不能“替换”或移除其他订阅。

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

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

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

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

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

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

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

简短的回答

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

答案很长

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

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

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

更多信息:

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

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

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

一些额外的说明:

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

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

暂无
暂无

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

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