区别委托和事件

以前

.NET 平台新手的开发人员在基于设计 delegates 与基于 events设计的设计之间做出决定时经常会苦苦挣扎。 委托或事件的选择通常比较难,因为这两种语言功能很相似。 事件甚至是使用委托的语言支持构建的。 事件处理程序声明委托类型。

两者都提供后期绑定方案:它们支持组件通过调用仅在运行时已知的方法进行通信的方案。 它们都支持单个和多个订阅者方法。 你可能会发现这些术语称为单播和多播支持。 它们都支持添加和删除处理程序的类似语法。 最后,引发事件和调用委托使用完全相同的方法调用语法。 它们甚至都支持相同的 Invoke() 方法语法与 ?. 运算符一起使用。

在所有相似之处下,很容易在决定使用哪个时遇到问题。

侦听事件是可选的

确定要使用的语言功能的最重要考虑因素是是否必须有附加的订阅者。 如果您的代码必须调用订阅者提供的代码,那么在需要实现回调时,应使用基于委托的设计。 如果代码能够在不调用任何订阅者的情况下完成所有工作,则应采用基于事件的设计。

请考虑本部分期间生成的示例。 必须为您使用 List.Sort() 构建的代码提供一个比较器函数,以正确排序元素。 必须与委托一起提供 LINQ 查询,以便确定要返回的元素。 二者均使用与委托一起生成的设计。

请考虑 Progress 事件。 它报告任务的进度。 无论是否有任何侦听器,任务将继续执行。 FileSearcher 是另一个示例。 即使没有附加事件订阅服务器,它仍将搜索和查找已找到的所有文件。 即使没有任何订阅服务器侦听事件,UX 控件仍正常工作。 它们都使用基于事件的设计。

返回值需要委托

另一个注意事项是委托方法所需的方法原型。 如你所见,用于事件的委托均具有无效的返回类型。 有一些习惯可以创建事件处理程序,这些处理程序通过修改事件参数对象的属性将信息传递回事件源。 虽然这些成语确实起作用,但它们与从方法返回值并不一样自然。

请注意,这两种启发法通常都存在:如果委托方法返回一个值,它会以某种方式影响算法。

事件具有专用调用

除包含事件以外的类只能添加和删除事件侦听器;只有包含事件的类才能调用该事件。 事件通常是公共类成员。 相比之下,委托通常作为参数传递,并存储为私有类成员(如果它们全部存储)。

事件侦听器通常具有较长的生存期

事件侦听器的较长生存期的理由不太充分。 但是,你可能会发现,当事件源在很长一段时间内引发事件时,基于事件的设计更自然。 可以查看许多系统上 UX 控件的基于事件的设计示例。 订阅事件后,事件源可以在程序的整个生命周期内引发事件。 (当不再需要事件时,可以取消订阅事件。)

将其与许多基于委托的设计(其中委托用作方法的参数,且在返回该方法后不再使用此委托)进行比较。

仔细评估

上述考虑因素不是严格规定。 相反,它们表示可帮助你确定哪种选择最适合特定用法的指南。 因为它们相似,你甚至可以创建原型,并考虑使用哪种方式更自然。 两者均能很好地处理后期绑定方案。 使用能与设计进行最佳通讯的一种。