Effective C#原则21:用委托来表示回调

我:“儿子,到院子里除草去,我要看会书。”

斯科特: “爸,我已经打扫过院子了。”

斯科特:“爸,我已经 把草放在除草机上了。”

斯科特:“爸,除草机不能启动了 。”

我:“让我来启动它。”

斯科特:“ 爸,我做好了。”

这个简单的交互展示了回调。我给了我儿子一个 任务,并且他可以报告状态来(重复的)打断我。而当我在等待他完成任务的每一 个部份时,我不用阻塞我自己的进程。他可以在有重要(或者事件)状态报告时, 可以定时的打断我,或者向我询求帮助。回调就是用于异步的提供服务器与客户 之间的信息反馈。它们可能在多线程中,或者可能是简单的提供一个同步更新点 。在C#里是用委托来表示回调的。

委托提供了一个类型安全的回调定义 。尽管委托大多数是为事件使用的,但这不应该是C#语言中唯一使用这一功能的 地方。任何时候,如果你想在两个类之间进行通信,而你又期望比使用接口有更 少的偶合性,那么委托是你正确的选择。委托可以让你在运行确定(回调)目标并 且通知用户。委托就是包含了某些方法的引用。这些方法可以是静态方法,也可 以是实例方法。使用委托,你可以在运行时确定与一个或者多个客户对象进行交 互。

多播委托包含了添加在这个委托上的所有单个函数调用。有两点要 注意的:它不是异常安全的,并且返回值总是委托上最后一个函数调用后返回的 值。

在多播委托调用的内部,每一个目标都会成功的调用。委托不会捕 获任何的异常,也就是说,在委托链中抛出的任何异常都会终止委托链的继续调 用。

在返回值上也存在一个简单的问题。你可以定义委托有返回值或者 是void。你可能会写一个回调函数来检测用户的异常中断:

public delegate bool ContinueProcessing();
public void LengthyOperation( ContinueProcessing pred )
{
  foreach( ComplicatedClass cl in _container )
 {
   cl.DoLengthyOperation();
  // Check for user abort:
  if (false == pred())
   return;
 }
}

在单 委托上这是工作的,但在多播委托上却是有问题的:

ContinueProcessing cp = new ContinueProcessing (
  CheckWithUser );
cp += new ContinueProcessing( CheckWithSystem );
c.LengthyOperation( cp );

从委托的调用上返回的值 ,其实是它的最后一个函数的调用上返回的值。其它所有的的返回值都被忽略。 即,从CheckWithUser()返回的断言被忽略。

你可以自己手动的设置两个 委托来调用两个函数。你所创建的每一个委托都包含有一个委托链。直接检测这 个委托链,并自己调用每一个委托:

public delegate bool ContinueProcessing();
public void LengthyOperation( ContinueProcessing pred )
{
 bool bContinue = true;
  foreach( ComplicatedClass cl in _container )
 {
   cl.DoLengthyOperation();
  foreach( ContinueProcessing pr in
   pred.GetInvocationList( ))
   bContinue &= pr ();
  if (false == bContinue)
   return;
 }
}

这时,我已经定义好了程序的语义,因此委托链上的每个委 托必须返回真以后,才能继续调用。

委托为运行时回调提供了最好的方 法,用户简单的实现用户对类的需求。你可以在运行时确定委托的目标。你可以 支持多个用户目标,这样,用户的回调就可以用.Net里的委托实现了。

返回教程目录

时间: 2024-09-13 11:39:49

Effective C#原则21:用委托来表示回调的相关文章

Effective C#原则22:用事件定义对外接口

可以用事件给你的类型定义一些外部接口.事件是基于委托的,因为委托可 以提供类型安全的函数签名到事件句柄上.加上大多数委托的例子都是使用事件 来说明的,以至于开发人员一开始都认为委托与事件是一回事.在原则21里,我 已经展示了一些不在事件上使用委托的例子.在你的类型与其它多个客户进行通 信时,为了完成它们的行为,你必须引发事件. 一个简单的例子,你正 在做一个日志类,就像一个信息发布机一样在应用程序里发布所有的消息.它接 受所有从程序源发布的消息,并且把这些消息发布到感兴趣的听众那里.这些听 众可

Effective C#原则35:选择重写函数而不是使用事件句柄

很多.Net类提供了两种不同的方法来控制一些系统的事件.那就是,要么添 加一个事件句柄:要么重写基类的虚函数.为什么要提供两个方法来完成同样的 事情呢?其实很简单,那就是因为不同的情况下要调用为的方法.在派生类的内 部,你应该总是重写虚函数.而对于你的用户,则应该限制他们只使用句柄来响 应一些不相关的对象上的事件. 例如你很了一个很不错的Windows应用程 序,它要响应鼠标点下的事件.在你的窗体类中,你可以选择重写OnMouseDown ()方法: public class MyForm :

详解C#中通过委托来实现回调函数功能的方法_C#教程

委托(delegate)是一种可以把引用存储为函数的类型,这类似于c++中的函数指针. 回调函数c++中的回调函数,就是用函数指针来实现的.类似的,c#中用委托,来实现回调函数的功能. 回调函数为什么被称为回调函数?比如你调用了一个函数,那么就叫调用,但是如果你在调用一个函数的时候,还需要把一个函数提供给该函数,让这个函数来调用你的函数,那么你提供的这个函数就被称为回调函数(callback). 对于python这样的动态语言而言,就没有c#,c++提供特殊的语法实现回调函数,因为在python

《Effective C#》:用委托实现回调

委托属于C#中的新名词,它的应用也非常广泛,例如事件就是委托最简单而又直接的例子. 那么首先说说什么是委托,其实委托在用过C或者C++的人看来就是函数指针,不过使用C#的大多数人都没有用过这两门语言,因此对委托的理解不是很深,对于委托可以简单的从字面去理解,即"委托别人去执行某些操作",也就是说执行一个操作,而这个操作过程自身并不知道,只是委托过来让你去执行而已. 参看如下这个例子. public delegate void HelloHandler( string Msg ); pr

Effective C#原则50:了解ECMA标准

ECMA标准是C#语言所有功能的官方说明.ECMA-334定义了C#语言1.0的标准, 你可以从The C# Programming Language这本书上学习C#2.0的计划(译注:现在 已经不是计划了),这本书的作者是Anders Hejlsberg, Scott Wiltamuth, 和 Peter Golde (Addison-Wesley, 2003).这本书是一个语言手册,而不是指南. 它详细说明了这门语言书面定义的每一个功能.每一种语言都只一种标记,可以 让你更加明白每一种语言的

Effective C#原则48:了解更多的工具和资源

对于C#以及.Net来说这是激动人心的时候.这些工具目前还是比较新的,整 个社区都在学习如何使用这些工具.一些资源可以帮助你提高你的知识,以及为 .Net和C#创建一个更大的知识社区.这些工具是我每天都向C#开发人员推荐的. 关于C#实践的全部内容还在写作当中,跟进它们而且不断了解相关的内容. 第一个应该在每一个C#开发人员的工具箱的工具是NUnit, 它可以在 www.nunit.org网站上找到.NUnit是一个自动进行单元测试的工具,功能和 JUnit很像.和其它大多数开发人员一样,我讨厌

Effective C#原则47:选择安全的代码

.Net运行时已经设计好了,一些怀有恶意的代码不能渗透到远程计算机上并 执行.目前一些分部式系统依懒于从远程机器上下载和执行代码.如果你可以通 过Internet或者以太网来发布你的软件,或者直接从web上运行,但你须要明白 CRL在你的程序集中的一些限制.如果CLR不是完全相信一个程序集,它会限制一 些的行为.这些调用代码要有访问安全认证(CAS).从另一方面来说,CLR强制要 求基于角色的安全认证,这样这些代码才能或者不能在基于一个特殊的角色帐号 下运行. 安全违例是运行时条件,编译器不能强

Effective C#原则45:选择强异常来保护程序

当你抛出异常时,你就在应用程序中引入了一个中断事件.而且危机到程序 的控制流程.使得期望的行为不能发生.更糟糕的是,你还要把清理工作留给最 终写代码捕获了异常的程序员.而当一个异常发生时,如果你可以从你所管理的 程序状态中直接捕获,那么你还可以采取一些有效的方法.谢天谢地,C#社区不 须要创建自己的异常安全策略,C++社区里的人已经为我们完成了所有的艰巨的 工作.以Tom Cargill的文章开头:"异常处理:一种错误的安全感觉, " 而且Herb Sutter,Scott Meyer

Effective C#原则43:请勿滥用反射

创建二进制的组件时,同时也意味着你要使用迟后绑定和反射来查找你所须 要的具有特殊功能代码.反射是一个很有力的工具,而且它让你可以写出可动态 配置的软件.使用反射,一个应用程序可以通过添加新的组件来更新功能,而这 些组件是在软件最开始发布时没有的.这是有利的. 这一伸缩性也带来 了一些复杂的问题,而且复杂问题的增加又会增加出现其它问题的可能.当你使 用反射时,你是围绕着C#的安全类型.然而,成员调用的参数和返回值是以 System.Object类型存在的.你必须在运行时确保这些类型是正确的.简单的